resources: Merge branch 'master' into develop
diff --git a/README.md b/README.md
index 1ef48a9..a6c339a 100755
--- a/README.md
+++ b/README.md
@@ -206,62 +206,87 @@
 <http://dist.gem5.org/dist/v20/test-progs/insttest/bin/riscv/linux/insttest-rv64m>
 
 
-# Resource: PThreads
+# Resource: simple
 
-## Compilation
+Simple single source file per executable userland or baremetal examples.
 
-The PThreads executables are compiled to aarch32, aarch64, riscv64, and x86.
+The toplevel executables under `src/simple` can be built for any ISA that we
+have a cross compiler for as mentioned under [Requirements](#requirements).
 
-### aarch32
+Examples that build only for some ISAs specific ones are present under
+`src/simple/<ISA>` subdirs, e.g. `src/simple/aarch64/`,
 
-To compile PThreads to aarch32 the [GNU ARM-32 Toolchain](
-#gnu-arm_32-bit-toolchain) must be installed.
+The ISA names are meant to match `uname -m`, e.g.:
 
-To compile:
+- `aarch64`
+- `arm`
+- `riscv`
+- `x86_64`
 
-```
-cd src/pthreads
-make -f Makefile.aarch32
-```
+You have to specify the path to the gem5 source code with `GEM5_ROOT` variable so that
+m5ops can be used from there. For example for a native build:
 
-The binaries can be found in the `src/pthreads/bin.aarch32` directory.
+    cd src/simple
+    make -j`nproc` GEM5_ROOT=../../../
 
-### aarch64
+The default of that variable is such that if you place this repository and the gem5
+repository in the same directory:
 
-To compile PThreads to aarch64 the [GNU ARM-64 Toolchain](
-#gnu-arm_64-bit-toolchain) must be installed.
+    ./gem5/
+    ./gem5-resources/
 
-To compile:
+you can omit that variable and build just with:
 
-```
-cd src/pthreads
-make -f Makefile.aarch64
-```
+    make
 
-The binaries can be found in the `src/pthreads/bin.aarch64` directory.
+After the building, the generated files are located under:
 
-### riscv64
+    ./out/<ISA>/
 
-To compile PThreads to RISCV64, the [RISCV GNU Compiler](
-#risc_v-gnu-compiler-toolchain) must be install
+For example, some of the userland executables built on x86 are:
 
-```
-cd src/pthreads
-make -f Makefile.riscv
-```
+    ./out/x86_64/user/hello.out
+    ./out/x86_64/user/x86_64/mwait.out
 
-The binaries can be found in the `src/pthreads/bin.riscv` directory.
+Or if you build for a different ISA:
 
-### x86
+    make ISA=aarch64
 
-To compile:
+some of the executables would be:
 
-```
-cd src/pthreads
-make -f Makefile.x86
-```
+    ./out/aarch64/user/hello.out
+    ./out/aarch64/user/aarch64/futex_ldxr_stxr.out
 
-The binaries can be found in the `src/pthreads/bin.x86` directory.
+By default, only userland executables are built. You can build just the baremetal
+ones instead with:
+
+    make ISA=aarch64 bare
+
+or both userland and baremetal with:
+
+    make ISA=aarch64 all
+
+A sample baremetal executable generated by this is:
+
+    out/aarch64/bare/m5_exit.out
+
+Only ISAs that have a corresponding `src/simple/bootloader/` file can build for
+baremetal, e.g. `src/simple/bootloader/aarch64.S`.
+
+Note that a some C source files can produce both a baremetal and an userland.
+For example `m5_exit.c` produces both:
+
+    out/aarch64/bare/m5_exit.out
+    out/aarch64/user/m5_exit.out
+
+However, since the regular userland toolchain is used rather than a more
+specialized baremetal toolchain, the C standard library is not available.
+Therefore, only very few C examples can build for baremetal, notably the ones
+that use m5ops.
+
+There are also examples that can only build for baremetal, e.g.
+`aarch64/semihost_exit` only builds for baremetal, as semihosting is not
+available on userland.
 
 ## Pre-build binaries
 
@@ -429,6 +454,36 @@
 
 The instructions to build the boot-tests disk image (`boot-exit`), the Linux binaries, and how to use gem5 run scripts to run boot-tests are available in this [README](src/boot-tests/README.md) file.
 
+# Resource: Insttest
+
+The Insttests test SPARC instructions.
+
+Creating the SPARC Insttest binary requires a SPARC cross compile. Instructions
+on creating a cross compiler can be found [here](
+https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler).
+
+## Compilation
+
+To compile:
+
+```
+cd src/insttest
+make
+```
+
+We provide a docker image with a pre-loaded SPARC cross compiler. To use:
+
+```
+cd src/insttest
+docker run --volume $(pwd):$(pwd) -w $(pwd) --rm gcr.io/gem5-test/sparc64-gnu-cross:latest make
+```
+
+The compiled binary can be found in `src/insttest/bin`.
+
+## Prebuild Binary
+
+<http://dist.gem5.org/dist/v20/test-progs/insttest/bin/sparc/linux/insttest>
+
 # Licensing
 
 Each project under the `src` is under a different license. Before using
@@ -436,8 +491,6 @@
 project's license.
 
 * **riscv-tests** : `src/riscv-tests/LICENSE`.
-* **insttests** : Consult individual copyright notices of source files in
-`src/insttests`.
 * **pthreads**: Consult individual copyright notices of source files in
 `src/pthreads`.
 * **square**: Consult individual copyright notices of source files in
@@ -458,4 +511,5 @@
 `src/npb`. The NAS Parallel Benchmarks utilize a permissive BSD-style license.
 * **boot-tests**: Consult individual copyright notices of source files in
 `src/boot-tests`.
-
+* **insttest**: Consult individual copyright notices of source files in
+`src/insttest`.
diff --git a/src/insttest/.gitignore b/src/insttest/.gitignore
index 5e56e04..ba077a4 100644
--- a/src/insttest/.gitignore
+++ b/src/insttest/.gitignore
@@ -1 +1 @@
-/bin
+bin
diff --git a/src/insttest/Makefile b/src/insttest/Makefile
index bfe7e66..786f7aa 100644
--- a/src/insttest/Makefile
+++ b/src/insttest/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 2016 The University of Virginia
+# Copyright (c) 2020 The Regents of the University of California
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -23,30 +23,22 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Authors: Alec Roelke
 
-CXX=riscv64-unknown-linux-gnu-g++
-CFLAGS=-std=gnu++11 -O3 -static -march=rv64gc
+CC := sparc64-linux-gcc
+CCFLAGS = -O3 -static
 
-TARGETS=rv64i rv64m rv64a rv64f rv64d rv64c
-PREFIX=bin
-BINARY=insttest
+BIN_DIR = ./bin
 
-all: $(TARGETS)
+TESTS = insttest
 
-$(TARGETS):
-	-mkdir -p $(PREFIX)
-	$(CXX) $< $(CFLAGS) -o $(PREFIX)/$(BINARY)-$@
+all: $(addprefix $(BIN_DIR)/,$(TESTS))
 
-rv64i: rv64i.cpp
-rv64m: rv64m.cpp
-rv64a: rv64a.cpp
-rv64f: rv64f.cpp
-rv64d: rv64d.cpp
-rv64c: rv64c.cpp
+$(BIN_DIR)/%: %.c
+	@mkdir -p $(BIN_DIR)
+	$(CC) -o $@ $(CCFLAGS) $^
 
 clean:
-	-rm -r $(PREFIX)
+	$(RM) -r $(BIN_DIR)
 
 .PHONY: all clean
+
diff --git a/src/insttest/insttest.c b/src/insttest/insttest.c
new file mode 100644
index 0000000..eef1c1c
--- /dev/null
+++ b/src/insttest/insttest.c
@@ -0,0 +1,205 @@
+#include <stdio.h>
+#include <stdint.h>
+
+void check(int pass) { printf(pass ? "Passed\n" : "Failed\n"); }
+
+void
+ldstubTest()
+{
+    printf("LDSTUB:\t\t");
+
+    uint8_t volatile mem = 0x11;
+    uint8_t rd = 0;
+    uint8_t mem_o = mem, rd_o = rd;
+
+    // Load one byte of memory into rd, zero extended, and set that byte in
+    // memory to all ones.
+    asm volatile ("ldstub [%[address]], %[rd]"
+            : [rd] "=r" (rd)
+            : [address] "r" (&mem));
+
+    check(mem == 0xff && rd == mem_o);
+}
+
+void
+swapTest()
+{
+    printf("SWAP:\t\t");
+
+    uint32_t volatile mem = 0x01234567;
+    uint32_t rd = 0x89ABCDEF;
+    uint32_t mem_o = mem, rd_o = rd;
+
+    // Swap the lower 32 bits of rd with a word of memory. Zero the upper
+    // 32 bits of rd.
+    asm volatile ("swap [%[address]], %[rd]"
+            : [rd] "+r" (rd)
+            : [address] "r" (&mem));
+
+    check(mem == rd_o && rd == mem_o);
+}
+
+void
+casFailTest()
+{
+    printf("CAS FAIL:\t");
+
+    uint32_t rd = 0x00112233;
+    uint32_t volatile mem = 0xffeeddcc;
+    uint32_t rs2 = 0;
+    uint32_t rd_o = rd, mem_o = mem, rs2_o = rs2;
+
+    // Compare the lower 32 bits of rs2 with a word of memory. Since they are
+    // different, leave memory unchanged and put the contents of memory in
+    // rd, zero extended.
+    asm volatile ("cas [%[address]], %[rs2], %[rd]"
+            : [rd] "+r" (rd)
+            : [address] "r" (&mem), [rs2] "r" (rs2));
+
+    check(mem == mem_o && rd == mem_o);
+}
+
+void
+casWorkTest()
+{
+    printf("CAS WORK:\t");
+
+    uint32_t rd = 0x00112233;
+    uint32_t volatile mem = 0xffeeddcc;
+    uint32_t rs2 = 0xffeeddcc;
+    uint32_t rd_o = rd, mem_o = mem, rs2_o = rs2;
+
+    // Compare the lower 32 bits of rs2 with a word of memory. Since they are
+    // equal, swap the value in lower 32 bits of rd with that word of memory.
+    // Zero the upper 32 bits of rd.
+    asm volatile ("cas [%[address]], %[rs2], %[rd]"
+            : [rd] "+r" (rd)
+            : [address] "r" (&mem), [rs2] "r" (rs2));
+
+    check(mem == rd_o && rd == mem_o);
+}
+
+void
+casxFailTest()
+{
+    printf("CASX FAIL:\t");
+
+    uint64_t rd = 0x0011223344556677;
+    uint64_t volatile mem = 0xffeeddccbbaa9988;
+    uint64_t rs2 = 0;
+    uint64_t rd_o = rd, mem_o = mem, rs2_o = rs2;
+
+    // Compare rs2 with a doubleword of memory. Since they are different, leave
+    // memory unchanged and put the contets of memory in rd.
+    asm volatile ("casx [%[address]], %[rs2], %[rd]"
+            : [rd] "+r" (rd)
+            : [address] "r" (&mem), [rs2] "r" (rs2));
+
+    check(mem == mem_o && rd == mem_o);
+}
+
+void
+casxWorkTest()
+{
+    printf("CASX WORK:\t");
+
+    uint64_t rd = 0x0011223344556677;
+    uint64_t volatile mem = 0xffeeddccbbaa9988;
+    uint64_t rs2 = 0xffeeddccbbaa9988;
+    uint64_t rd_o = rd, mem_o = mem, rs2_o = rs2;
+
+    // Compare rs2 with a doubleword of memory. Since they are equal, swap rd
+    // with that doubleword of memory.
+    asm volatile ("casx [%[address]], %[rs2], %[rd]"
+            : [rd] "+r" (rd)
+            : [address] "r" (&mem), [rs2] "r" (rs2));
+
+    check(mem == rd_o && rd == mem_o);
+}
+
+void
+ldtxTest()
+{
+    printf("LDTX:\t\t");
+
+    uint64_t volatile mem[2] __attribute__((aligned(16))) = {
+        0xffeeddccbbaa9988, 0x0011223344556677 };
+    uint64_t rd1 = 0, rd2 = 0;
+    uint64_t mem_o[2] = { mem[0], mem[1] };
+
+    // LDDA will normally load a doubleword of memory into a register pair,
+    // but when told to use ASI e2 (ASI_TWINX_PRIMARY) it will load two
+    // doublewords which it will put into the register pair.
+    asm volatile (
+            "ldda [%[address]]0xe2, %%g2\n"
+            "mov %%g2, %[rd1]\n"
+            "mov %%g3, %[rd2]\n"
+            : [rd1] "=r" (rd1), [rd2] "=r" (rd2)
+            : [address] "r" (&mem[0])
+            : "%g2", "%g3");
+
+    check(rd1 == mem_o[0] && rd2 == mem_o[1]);
+}
+
+void
+ldtwTest()
+{
+    printf("LDTW:\t\t");
+
+    uint32_t volatile mem[2] __attribute__((aligned(8))) = {
+        0x89abcdef, 0x01234567 };
+    uint32_t rd1 = 0, rd2 = 0;
+    uint64_t mem_o[2] = { mem[0], mem[1] };
+
+    // Load two adjacent words from memory into the lower 32 bits of a pair
+    // of registers, and zero their upper 32 bits.
+    asm volatile (
+            "ldd [%[address]], %%g2\n"
+            "mov %%g2, %[rd1]\n"
+            "mov %%g3, %[rd2]\n"
+            : [rd1] "=r" (rd1), [rd2] "=r" (rd2)
+            : [address] "r" (&mem[0])
+            : "%g2", "%g3");
+    check(rd1 == mem_o[0] && rd2 == mem_o[1]);
+}
+
+void
+sttwTest()
+{
+    printf("STTW:\t\t");
+
+    uint32_t volatile mem[2] __attribute__((aligned(8))) = { 0, 0 };
+    uint64_t rd1 = 0x89abcdef, rd2 = 0x1234567;
+    uint64_t rd1_o = rd1, rd2_o = rd2;
+
+    // Store the lower 32 bits of a pair of registers into a single doubleword
+    // of memory.
+    asm volatile (
+            "mov %[rd1], %%g2\n"
+            "mov %[rd2], %%g3\n"
+            "std %%g2, [%[address]]"
+            :
+            : [rd1] "r" (rd1), [rd2] "r" (rd2), [address] "r" (&mem[0])
+            : "%g2", "%g3");
+
+    check(mem[0] == rd1_o && mem[1] == rd2_o);
+}
+
+int
+main()
+{
+    printf("Begining test of difficult SPARC instructions...\n");
+
+    ldstubTest();
+    swapTest();
+    casFailTest();
+    casWorkTest();
+    casxFailTest();
+    casxWorkTest();
+    ldtxTest();
+    ldtwTest();
+    sttwTest();
+
+    printf("Done\n");
+    return 0;
+}
diff --git a/src/insttest/insttest.h b/src/insttest/insttest.h
deleted file mode 100644
index be1b86e..0000000
--- a/src/insttest/insttest.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#pragma once
-
-#include <cmath>
-#include <cstdlib>
-#include <functional>
-#include <iostream>
-#include <string>
-
-#define IOP(inst, rd, rs1, imm) \
-    asm volatile(inst " %0,%1,%2" : "=r" (rd) : "r" (rs1), "i" (imm))
-
-#define ROP(inst, rd, rs1, rs2) \
-    asm volatile(inst " %0,%1,%2" : "=r" (rd) : "r" (rs1), "r" (rs2))
-
-#define FROP(inst, fd, fs1, fs2) \
-    asm volatile(inst " %0,%1,%2" : "=f" (fd) : "f" (fs1), "f" (fs2))
-
-#define FR4OP(inst, fd, fs1, fs2, fs3) \
-    asm volatile(inst " %0,%1,%2,%3" \
-            : "=f" (fd) \
-            : "f" (fs1), "f" (fs2), "f" (fs3))
-
-template<typename A, typename B> std::ostream&
-operator<<(std::ostream& os, const std::pair<A, B>& p)
-{
-    return os << '(' << p.first << ", " << p.second << ')';
-}
-
-namespace insttest
-{
-
-template<typename T> void
-expect(const T& expected, std::function<T()> func,
-        const std::string& test)
-{
-    using namespace std;
-
-    T result = func();
-    cout << test << ": ";
-    if (result == expected) {
-        cout << "PASS" << endl;
-    } else {
-        cout << "\033[1;31mFAIL\033[0m (expected " << expected << "; found " <<
-            result << ")" << endl;
-    }
-}
-
-} // namespace insttest
diff --git a/src/insttest/rv64a.cpp b/src/insttest/rv64a.cpp
deleted file mode 100644
index a6e226c..0000000
--- a/src/insttest/rv64a.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#include <cstdint>
-#include <limits>
-
-#include "insttest.h"
-#include "rv64a.h"
-
-int main()
-{
-    using namespace std;
-    using namespace insttest;
-
-    // Memory (LR.W, SC.W)
-    expect<pair<int64_t, int64_t>>({-1, 256}, []{
-            int32_t mem = -1;
-            int64_t rs2 = 256;
-            int64_t rd;
-            pair<int64_t, uint64_t> result;
-            do {
-                rd = A::lr_w(mem);
-                result = A::sc_w(rs2, mem);
-            } while (result.second == 1);
-            return pair<int64_t, uint64_t>(rd, result.first);
-        }, "lr.w/sc.w");
-    expect<pair<bool, int64_t>>({true, 200}, []{
-            int32_t mem = 200;
-            pair<int64_t, uint64_t> result = A::sc_w(50, mem);
-            return pair<bool, int64_t>(result.second == 1, mem);
-        }, "sc.w, no preceding lr.d");
-
-    // AMOSWAP.W
-    expect<pair<int64_t, int64_t>>({65535, 255},
-            []{return A::amoswap_w(255, 65535);}, "amoswap.w");
-    expect<pair<int64_t, int64_t>>({0xFFFFFFFF, -1},
-            []{return A::amoswap_w(0xFFFFFFFF, 0xFFFFFFFF);},
-            "amoswap.w, sign extend");
-    expect<pair<int64_t, int64_t>>({0x0000000180000000LL, -1},
-            []{return A::amoswap_w(0x00000001FFFFFFFFLL,
-                    0x7FFFFFFF80000000LL);},
-            "amoswap.w, truncate");
-
-    // AMOADD.W
-    expect<pair<int64_t, int64_t>>({256, 255},
-            []{return A::amoadd_w(255, 1);}, "amoadd.w");
-    expect<pair<int64_t, int64_t>>({0, -1},
-            []{return A::amoadd_w(0xFFFFFFFF, 1);},
-            "amoadd.w, truncate/overflow");
-    expect<pair<int64_t, int64_t>>({0xFFFFFFFF, 0x7FFFFFFF},
-            []{return A::amoadd_w(0x7FFFFFFF, 0x80000000);},
-            "amoadd.w, sign extend");
-
-    // AMOXOR.W
-    expect<pair<uint64_t, uint64_t>>({0xFFFFFFFFAAAAAAAALL, -1},
-            []{return A::amoxor_w(-1, 0x5555555555555555LL);},
-            "amoxor.w, truncate");
-    expect<pair<uint64_t, uint64_t>>({0x80000000, -1},
-            []{return A::amoxor_w(0xFFFFFFFF, 0x7FFFFFFF);},
-            "amoxor.w, sign extend");
-
-    // AMOAND.W
-    expect<pair<uint64_t, uint64_t>>({0xFFFFFFFF00000000LL, -1},
-            []{return A::amoand_w(-1, 0);}, "amoand.w, truncate");
-    expect<pair<uint64_t, uint64_t>>({0x0000000080000000LL, -1},
-            []{return A::amoand_w(0xFFFFFFFF,numeric_limits<int32_t>::min());},
-            "amoand.w, sign extend");
-
-    // AMOOR.W
-    expect<pair<uint64_t, uint64_t>>({0x00000000FFFFFFFFLL, 0},
-            []{return A::amoor_w(0, -1);}, "amoor.w, truncate");
-    expect<pair<uint64_t, uint64_t>>({0x0000000080000000LL, 0},
-            []{return A::amoor_w(0, numeric_limits<int32_t>::min());},
-            "amoor.w, sign extend");
-
-    // AMOMIN.W
-    expect<pair<int64_t, int64_t>>({0x7FFFFFFF00000001LL, 1},
-            []{return A::amomin_w(0x7FFFFFFF00000001LL, 0xFFFFFFFF000000FF);},
-            "amomin.w, truncate");
-    expect<pair<int64_t, int64_t>>({0x00000000FFFFFFFELL, -1},
-            []{return A::amomin_w(0xFFFFFFFF, -2);}, "amomin.w, sign extend");
-
-    // AMOMAX.W
-    expect<pair<int64_t, int64_t>>({0x70000000000000FFLL, 1},
-            []{return A::amomax_w(0x7000000000000001LL,0x7FFFFFFF000000FFLL);},
-            "amomax.w, truncate");
-    expect<pair<int64_t, int64_t>>({-1, numeric_limits<int32_t>::min()},
-            []{return A::amomax_w(numeric_limits<int32_t>::min(), -1);},
-            "amomax.w, sign extend");
-
-    // AMOMINU.W
-    expect<pair<uint64_t, uint64_t>>({0x0FFFFFFF000000FFLL, -1},
-            []{return A::amominu_w(0x0FFFFFFFFFFFFFFFLL, 0xFFFFFFFF000000FF);},
-            "amominu.w, truncate");
-    expect<pair<uint64_t, uint64_t>>({0x0000000080000000LL, -1},
-            []{return A::amominu_w(0x00000000FFFFFFFFLL, 0x80000000);},
-            "amominu.w, sign extend");
-
-    // AMOMAXU.W
-    expect<pair<uint64_t, uint64_t>>({-1, 0},
-            []{return A::amomaxu_w(0xFFFFFFFF00000000LL,
-                    0x00000000FFFFFFFFLL);},
-            "amomaxu.w, truncate");
-    expect<pair<uint64_t, uint64_t>>(
-            {0xFFFFFFFF, numeric_limits<int32_t>::min()},
-            []{return A::amomaxu_w(0x80000000, 0xFFFFFFFF);},
-            "amomaxu.w, sign extend");
-
-    // Memory (LR.D, SC.D)
-    expect<pair<int64_t, int64_t>>({-1, 256}, []{
-            int64_t mem = -1;
-            int64_t rs2 = 256;
-            int64_t rd;
-            pair<int64_t, uint64_t> result;
-            do {
-                rd = A::lr_d(mem);
-                result = A::sc_d(rs2, mem);
-            } while (result.second == 1);
-            return pair<int64_t, uint64_t>(rd, result.first);
-        }, "lr.d/sc.d");
-    expect<pair<bool, int64_t>>({true, 200}, []{
-            int64_t mem = 200;
-            pair<int64_t, uint64_t> result = A::sc_d(50, mem);
-            return pair<bool, int64_t>(result.second == 1, mem);
-        }, "sc.d, no preceding lr.d");
-
-    // AMOSWAP.D
-    expect<pair<int64_t, int64_t>>({1, -1}, []{return A::amoswap_d(-1, 1);},
-            "amoswap.d");
-
-    // AMOADD.D
-    expect<pair<int64_t, int64_t>>({0x7000000000000000LL,0x0FFFFFFFFFFFFFFFLL},
-            []{return A::amoadd_d(0x0FFFFFFFFFFFFFFFLL,0x6000000000000001LL);},
-            "amoadd.d");
-    expect<pair<int64_t, int64_t>>({0, 0x7FFFFFFFFFFFFFFFLL},
-            []{return A::amoadd_d(0x7FFFFFFFFFFFFFFFLL,0x8000000000000001LL);},
-            "amoadd.d, overflow");
-
-    // AMOXOR.D
-    expect<pair<int64_t, int64_t>>({-1, 0xAAAAAAAAAAAAAAAALL},
-            []{return A::amoxor_d(0xAAAAAAAAAAAAAAAALL,0x5555555555555555LL);},
-            "amoxor.d (1)");
-    expect<pair<int64_t, int64_t>>({0, 0xAAAAAAAAAAAAAAAALL},
-            []{return A::amoxor_d(0xAAAAAAAAAAAAAAAALL,0xAAAAAAAAAAAAAAAALL);},
-            "amoxor.d (0)");
-
-    // AMOAND.D
-    expect<pair<int64_t, int64_t>>({0xAAAAAAAAAAAAAAAALL, -1},
-            []{return A::amoand_d(-1, 0xAAAAAAAAAAAAAAAALL);}, "amoand.d");
-
-    // AMOOR.D
-    expect<pair<int64_t, int64_t>>({-1, 0xAAAAAAAAAAAAAAAALL},
-            []{return A::amoor_d(0xAAAAAAAAAAAAAAAALL, 0x5555555555555555LL);},
-            "amoor.d");
-
-    // AMOMIN.D
-    expect<pair<int64_t, int64_t>>({-1, -1},
-            []{return A::amomin_d(-1, 0);}, "amomin.d");
-
-    // AMOMAX.D
-    expect<pair<int64_t, int64_t>>({0, -1}, []{return A::amomax_d(-1, 0);},
-            "amomax.d");
-
-    // AMOMINU.D
-    expect<pair<uint64_t, uint64_t>>({0, -1},
-            []{return A::amominu_d(-1, 0);}, "amominu.d");
-
-    // AMOMAXU.D
-    expect<pair<uint64_t, uint64_t>>({-1, -1}, []{return A::amomaxu_d(-1, 0);},
-            "amomaxu.d");
-
-    return 0;
-}
diff --git a/src/insttest/rv64a.h b/src/insttest/rv64a.h
deleted file mode 100644
index cfd1fd8..0000000
--- a/src/insttest/rv64a.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#pragma once
-
-#include <cstdint>
-#include <tuple>
-
-#include "insttest.h"
-
-namespace A
-{
-
-inline int64_t
-lr_w(int32_t& mem)
-{
-    int64_t r = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("lr.w %0,(%1)" : "=r" (r) : "r" (addr) : "memory");
-    return r;
-}
-
-inline std::pair<int64_t, uint64_t>
-sc_w(int64_t rs2, int32_t& mem)
-{
-    uint64_t addr = (uint64_t)&mem;
-    uint64_t rd = -1;
-    asm volatile("sc.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<int64_t, int64_t>
-amoswap_w(int64_t mem, int64_t rs2)
-{
-    int64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoswap.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<int64_t, int64_t>
-amoadd_w(int64_t mem, int64_t rs2)
-{
-    int64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoadd.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amoxor_w(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoxor.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amoand_w(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoand.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amoor_w(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoor.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<int64_t, int64_t>
-amomin_w(int64_t mem, int64_t rs2)
-{
-    int64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amomin.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<int64_t, int64_t>
-amomax_w(int64_t mem, int64_t rs2)
-{
-    int64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amomax.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amominu_w(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amominu.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amomaxu_w(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amomaxu.w %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline int64_t
-lr_d(int64_t& mem)
-{
-    int64_t r = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("lr.d %0,(%1)" : "=r" (r) : "r" (addr) : "memory");
-    return r;
-}
-
-inline std::pair<int64_t, uint64_t>
-sc_d(int64_t rs2, int64_t& mem)
-{
-    uint64_t addr = (uint64_t)&mem;
-    uint64_t rd = -1;
-    asm volatile("sc.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<int64_t, int64_t>
-amoswap_d(int64_t mem, int64_t rs2)
-{
-    int64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoswap.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<int64_t, int64_t>
-amoadd_d(int64_t mem, int64_t rs2)
-{
-    int64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoadd.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amoxor_d(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoxor.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amoand_d(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoand.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amoor_d(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amoor.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<int64_t, int64_t>
-amomin_d(int64_t mem, int64_t rs2)
-{
-    int64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amomin.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<int64_t, int64_t>
-amomax_d(int64_t mem, int64_t rs2)
-{
-    int64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amomax.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amominu_d(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amominu.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-inline std::pair<uint64_t, uint64_t>
-amomaxu_d(uint64_t mem, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    uint64_t addr = (uint64_t)&mem;
-    asm volatile("amomaxu.d %0,%2,(%1)"
-            : "=r" (rd)
-            : "r" (addr), "r" (rs2)
-            : "memory");
-    return {mem, rd};
-}
-
-} // namespace A
diff --git a/src/insttest/rv64c.cpp b/src/insttest/rv64c.cpp
deleted file mode 100644
index 869784d..0000000
--- a/src/insttest/rv64c.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (c) 2017 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#include <limits>
-
-#include "insttest.h"
-#include "rv64c.h"
-#include "rv64d.h"
-
-int main()
-{
-    using namespace insttest;
-    using namespace std;
-
-    // C.LWSP
-    expect<bool>(true, []{
-        uint64_t lw = 0, lwsp = -1;
-        int64_t i = 16;
-        asm volatile("lw %0,%2(sp);"
-                     "c.lwsp %1,%2(sp);"
-                     : "=r" (lw), "=r" (lwsp)
-                     : "i" (i));
-        return lw == lwsp;
-    }, "c.lwsp");
-
-    // C.LDSP
-    expect<bool>(true, []{
-        uint64_t ld = 0, ldsp = -1;
-        int64_t i = 8;
-        asm volatile("ld %0,%2(sp);"
-                     "c.ldsp %1,%2(sp);"
-                     : "=r" (ld), "=r" (ldsp)
-                     : "i" (i));
-        return ld == ldsp;
-    }, "c.ldsp");
-
-    // C.FLDSP
-    expect<bool>(true, []{
-        double fld = 0.0, fldsp = -1.0;
-        int64_t i = 32;
-        asm volatile("fld %0,%2(sp);"
-                     "c.fldsp %1,%2(sp);"
-                     : "=f" (fld), "=f" (fldsp)
-                     : "i" (i));
-        return D::bits(fld) == D::bits(fldsp);
-    }, "c.fldsp");
-
-    // C.SWSP
-    expect<bool>(true, []{
-        int64_t value = -1, result = 0;
-        asm volatile("addi sp,sp,-8;"
-                     "c.swsp %1,8(sp);"
-                     "lw %0,8(sp);"
-                     "addi sp,sp,8;"
-                     : "=r" (result)
-                     : "r" (value)
-                     : "memory");
-        return value == result;
-    }, "c.swsp");
-
-    // C.SDSP
-    expect<bool>(true, []{
-        int64_t value = -1, result = 0;
-        asm volatile("addi sp,sp,-8;"
-                     "c.sdsp %1,8(sp);"
-                     "ld %0,8(sp);"
-                     "addi sp,sp,8;"
-                     : "=r" (result)
-                     : "r" (value)
-                     : "memory");
-        return value == result;
-    }, "c.sdsp");
-
-    // C.FSDSP
-    expect<bool>(true, []{
-        double value = 0.1, result = numeric_limits<double>::signaling_NaN();
-        asm volatile("addi sp,sp,-8;"
-                     "c.fsdsp %1,8(sp);"
-                     "fld %0,8(sp);"
-                     "addi sp,sp,8;"
-                     : "=f" (result)
-                     : "f" (value)
-                     : "memory");
-        return value == result;
-    }, "c.fsdsp");
-
-    // C.LW, C.LD, C.FLD
-    expect<int64_t>(458752,
-            []{return C::c_load<int32_t, int64_t>(0x00070000);},
-            "c.lw, positive");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return C::c_load<int32_t, int64_t>(0x80000000);},
-            "c.lw, negative");
-    expect<int64_t>(30064771072,
-            []{return C::c_load<int64_t, int64_t>(30064771072);}, "c.ld");
-    expect<double>(3.1415926, []{return C::c_load<double, double>(3.1415926);},
-        "c.fld");
-
-    // C.SW, C.SD, C.FSD
-    expect<uint32_t>(0xFFFFFFFF, []{return C::c_store<int32_t>(-1);}, "c.sw");
-    expect<uint64_t>(-1, []{return C::c_store<int64_t>(-1);}, "c.sd");
-    expect<double>(1.61803398875,
-            []{return C::c_store<double>(1.61803398875);}, "c.fsd");
-
-    // C.J, C.JR, C.JALR
-    expect<bool>(true, []{return C::c_j();}, "c.j");
-    expect<bool>(true, []{return C::c_jr();}, "c.jr");
-    expect<bool>(true, []{return C::c_jalr();}, "c.jalr");
-
-    // C.BEQZ
-    expect<bool>(true, []{return C::c_beqz(0);}, "c.beqz, zero");
-    expect<bool>(false, []{return C::c_beqz(7);}, "c.beqz, not zero");
-
-    // C.BNEZ
-    expect<bool>(true, []{return C::c_bnez(15);}, "c.bnez, not zero");
-    expect<bool>(false, []{return C::c_bnez(0);}, "c.bnez, zero");
-
-    // C.LI
-    expect<int64_t>(1, []{return C::c_li(1);}, "c.li");
-    expect<int64_t>(-1, []{return C::c_li(-1);}, "c.li, sign extend");
-
-    // C.LUI
-    expect<int64_t>(4096, []{return C::c_lui(1);}, "c.lui");
-    // Note that sign extension can't be tested here because apparently the
-    // compiler doesn't allow the 6th (sign) bit of the immediate to be 1
-
-    // C.ADDI
-    expect<int64_t>(15, []{return C::c_addi(7, 8);}, "c.addi");
-
-    // C.ADDIW
-    expect<int64_t>(15, []{return C::c_addiw(8, 7);}, "c.addiw");
-    expect<int64_t>(1, []{return C::c_addiw(0xFFFFFFFF, 2);},
-            "c.addiw, overflow");
-    expect<int64_t>(1, []{return C::c_addiw(0x100000001, 0);},
-            "c.addiw, truncate");
-
-    // C.ADDI16SP
-    expect<bool>(true, []{
-        uint64_t sp = 0, rd = 0;
-        const int16_t i = 4;
-        asm volatile("mv %0,sp;"
-                     "c.addi16sp sp,%2;"
-                     "mv %1,sp;"
-                     "mv sp,%0;"
-                     : "+r" (sp), "=r" (rd)
-                     : "i" (i*16));
-        return rd == sp + i*16;
-    }, "c.addi16sp");
-
-    // C.ADDI4SPN
-    expect<bool>(true, []{
-        uint64_t sp = 0, rd = 0;
-        const int16_t i = 3;
-        asm volatile("mv %0,sp;"
-                     "c.addi4spn %1,sp,%2;"
-                     : "=r" (sp), "=r" (rd)
-                     : "i" (i*4));
-        return rd == sp + i*4;
-    }, "c.addi4spn");
-
-    // C.SLLI
-    expect<uint64_t>(16, []{return C::c_slli(1, 4);}, "c.slli");
-    expect<uint64_t>(0, []{return C::c_slli(8, 61);}, "c.slli, overflow");
-
-    // C.SRLI
-    expect<uint64_t>(4, []{return C::c_srli(128, 5);}, "c.srli");
-    expect<uint64_t>(0, []{return C::c_srli(128, 8);}, "c.srli, overflow");
-    expect<uint64_t>(1, []{return C::c_srli(-1, 63);}, "c.srli, -1");
-
-    // C.SRAI
-    expect<uint64_t>(4, []{return C::c_srai(128, 5);}, "c.srai");
-    expect<uint64_t>(0, []{return C::c_srai(128, 8);}, "c.srai, overflow");
-    expect<uint64_t>(-1, []{return C::c_srai(-2, 63);}, "c.srai, -1");
-
-    // C.ANDI
-    expect<uint64_t>(0, []{return C::c_andi(-1, 0);}, "c.andi (0)");
-    expect<uint64_t>(0x1234567812345678ULL,
-            []{return C::c_andi(0x1234567812345678ULL, -1);}, "c.andi (1)");
-
-    // C.MV
-    expect<int64_t>(1024, []{return C::c_mv(1024);}, "c.mv");
-
-    // C.ADD
-    expect<int64_t>(15, []{return C::c_add(10, 5);}, "c.add");
-
-    // C.AND
-    expect<uint64_t>(0, []{return C::c_and(-1, 0);}, "c.and (0)");
-    expect<uint64_t>(0x1234567812345678ULL,
-            []{return C::c_and(0x1234567812345678ULL, -1);}, "c.and (-1)");
-
-    // C.OR
-    expect<uint64_t>(-1,
-            []{return C::c_or(0xAAAAAAAAAAAAAAAAULL,
-                    0x5555555555555555ULL);},
-            "c.or (1)");
-    expect<uint64_t>(0xAAAAAAAAAAAAAAAAULL,
-            []{return C::c_or(0xAAAAAAAAAAAAAAAAULL,
-                    0xAAAAAAAAAAAAAAAAULL);},
-            "c.or (A)");
-
-    // C.XOR
-    expect<uint64_t>(-1,
-            []{return C::c_xor(0xAAAAAAAAAAAAAAAAULL,
-                    0x5555555555555555ULL);},
-            "c.xor (1)");
-    expect<uint64_t>(0,
-            []{return C::c_xor(0xAAAAAAAAAAAAAAAAULL,
-                    0xAAAAAAAAAAAAAAAAULL);},
-            "c.xor (0)");
-
-    // C.SUB
-    expect<int64_t>(65535, []{return C::c_sub(65536, 1);}, "c.sub");
-
-    // C.ADDW
-    expect<int64_t>(1073742078, []{return C::c_addw(0x3FFFFFFF, 255);},
-            "c.addw");
-    expect<int64_t>(-1, []{return C::c_addw(0x7FFFFFFF, 0x80000000);},
-            "c.addw, overflow");
-    expect<int64_t>(65536, []{return C::c_addw(0xFFFFFFFF0000FFFFLL, 1);},
-            "c.addw, truncate");
-
-    // C.SUBW
-    expect<int64_t>(65535, []{return C::c_subw(65536, 1);}, "c.subw");
-    expect<int64_t>(-1, []{return C::c_subw(0x7FFFFFFF, 0x80000000);},
-            "c.subw, \"overflow\"");
-    expect<int64_t>(0,
-            []{return C::c_subw(0xAAAAAAAAFFFFFFFFULL,0x55555555FFFFFFFFULL);},
-            "c.subw, truncate");
-}
\ No newline at end of file
diff --git a/src/insttest/rv64c.h b/src/insttest/rv64c.h
deleted file mode 100644
index 26d9009..0000000
--- a/src/insttest/rv64c.h
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (c) 2017 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#pragma once
-
-#include <cstdint>
-#include <type_traits>
-
-#include "insttest.h"
-
-#define CIOP(op, r, imm) asm volatile(op " %0,%1" : "+r" (r) : "i" (imm));
-#define CROP(op, rd, rs) asm volatile(op " %0,%1" : "+r" (rd) : "r" (rs))
-
-namespace C
-{
-
-inline int64_t
-c_li(const int8_t imm)
-{
-    int64_t rd = 0;
-    CIOP("c.li", rd, imm);
-    return rd;
-}
-
-inline int64_t
-c_lui(const int8_t imm)
-{
-    int64_t rd = 0;
-    CIOP("c.lui", rd, imm);
-    return rd;
-}
-
-inline int64_t
-c_addi(int64_t r, const int8_t imm)
-{
-    CIOP("c.addi", r, imm);
-    return r;
-}
-
-inline int64_t
-c_addiw(int64_t r, const int8_t imm)
-{
-    CIOP("c.addiw", r, imm);
-    return r;
-}
-
-inline uint64_t
-c_addi4spn(const int16_t imm)
-{
-    uint64_t rd = 0;
-    asm volatile("c.addi4spn %0,sp,%1" : "=r" (rd) : "i" (imm));
-    return rd;
-}
-
-inline uint64_t
-c_slli(uint64_t r, uint8_t shamt)
-{
-    CIOP("c.slli", r, shamt);
-    return r;
-}
-
-inline uint64_t
-c_srli(uint64_t r, uint8_t shamt)
-{
-    CIOP("c.srli", r, shamt);
-    return r;
-}
-
-inline int64_t
-c_srai(int64_t r, uint8_t shamt)
-{
-    CIOP("c.srai", r, shamt);
-    return r;
-}
-
-inline uint64_t
-c_andi(uint64_t r, uint8_t imm)
-{
-    CIOP("c.andi", r, imm);
-    return r;
-}
-
-inline int64_t
-c_mv(int64_t rs)
-{
-    int64_t rd = 0;
-    CROP("c.mv", rd, rs);
-    return rd;
-}
-
-inline int64_t
-c_add(int64_t rd, int64_t rs)
-{
-    CROP("c.add", rd, rs);
-    return rd;
-}
-
-inline uint64_t
-c_and(int64_t rd, int64_t rs)
-{
-    CROP("c.and", rd, rs);
-    return rd;
-}
-
-inline uint64_t
-c_or(int64_t rd, int64_t rs)
-{
-    CROP("c.or", rd, rs);
-    return rd;
-}
-
-inline uint64_t
-c_xor(int64_t rd, int64_t rs)
-{
-    CROP("c.xor", rd, rs);
-    return rd;
-}
-
-inline int64_t
-c_sub(int64_t rd, int64_t rs)
-{
-    CROP("c.sub", rd, rs);
-    return rd;
-}
-
-inline int64_t
-c_addw(int64_t rd, int64_t rs)
-{
-    CROP("c.addw", rd, rs);
-    return rd;
-}
-
-inline int64_t
-c_subw(int64_t rd, int64_t rs)
-{
-    CROP("c.subw", rd, rs);
-    return rd;
-}
-
-template<typename M, typename R> inline R
-c_load(M m)
-{
-    R r = 0;
-    switch (sizeof(M))
-    {
-      case 4:
-        asm volatile("c.lw %0,0(%1)" : "=r" (r) : "r" (&m) : "memory");
-        break;
-      case 8:
-        if (std::is_floating_point<M>::value)
-            asm volatile("c.fld %0,0(%1)" : "=f" (r) : "r" (&m) : "memory");
-        else
-            asm volatile("c.ld %0,0(%1)" : "=r" (r) : "r" (&m) : "memory");
-        break;
-    }
-    return r;
-}
-
-template<typename M> inline M
-c_store(const M& rs)
-{
-    M mem = 0;
-    switch (sizeof(M))
-    {
-      case 4:
-        asm volatile("c.sw %0,0(%1)" : : "r" (rs), "r" (&mem) : "memory");
-        break;
-      case 8:
-        if (std::is_floating_point<M>::value)
-            asm volatile("c.fsd %0,0(%1)" : : "f" (rs), "r" (&mem) : "memory");
-        else
-            asm volatile("c.sd %0,0(%1)" : : "r" (rs), "r" (&mem) : "memory");
-        break;
-    }
-    return mem;
-}
-
-inline bool
-c_j()
-{
-    asm volatile goto("c.j %l[jallabel]" : : : : jallabel);
-    return false;
-  jallabel:
-    return true;
-}
-
-inline bool
-c_jr()
-{
-    uint64_t a = 0;
-    asm volatile("auipc %0,0;"
-                 "c.addi %0,12;"
-                 "c.jr %0;"
-                 "addi %0,zero,0;"
-                 "addi %0,%0,0;"
-                 : "+r" (a));
-    return a > 0;
-}
-
-inline bool
-c_jalr()
-{
-    int64_t a = 0;
-    asm volatile("auipc %0,0;"
-                 "c.addi %0,12;"
-                 "c.jalr %0;"
-                 "addi %0,zero,0;"
-                 "sub %0,ra,%0;"
-                 : "+r" (a)
-                 :
-                 : "ra");
-    return a == -4;
-}
-
-inline bool
-c_beqz(int64_t a)
-{
-    asm volatile goto("c.beqz %0,%l[beqlabel]"
-            :
-            : "r" (a)
-            :
-            : beqlabel);
-    return false;
-  beqlabel:
-    return true;
-}
-
-inline bool
-c_bnez(int64_t a)
-{
-    asm volatile goto("c.bnez %0,%l[beqlabel]"
-            :
-            : "r" (a)
-            :
-            : beqlabel);
-    return false;
-  beqlabel:
-    return true;
-}
-
-} // namespace C
\ No newline at end of file
diff --git a/src/insttest/rv64d.cpp b/src/insttest/rv64d.cpp
deleted file mode 100644
index adb62d2..0000000
--- a/src/insttest/rv64d.cpp
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#include <cstdint>
-#include <limits>
-
-#include "insttest.h"
-#include "rv64d.h"
-#include "rv64f.h"
-
-int main()
-{
-    using namespace std;
-    using namespace insttest;
-
-    // Memory (FLD, FSD)
-    expect<double>(3.1415926, []{return D::load(3.1415926);}, "fld");
-    expect<double>(1.61803398875, []{return D::store(1.61803398875);}, "fsd");
-
-    // FMADD.D
-    expect<double>(D::number(0x4019FD5AED13B1CEULL),
-                []{return D::fmadd_d(3.1415926, 1.61803398875,1.41421356237);},
-                "fmadd.d");
-    expect<bool>(true, []{
-            double fd = D::fmadd_d(numeric_limits<double>::quiet_NaN(), 3.14,
-                    1.816);
-            return D::isquietnan(fd);
-        }, "fmadd.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fmadd_d(3.14,
-                    numeric_limits<double>::signaling_NaN(), 1.816);
-            return D::isquietnan(fd);
-        }, "fmadd.d, signaling NaN");
-    expect<double>(numeric_limits<double>::infinity(),
-        []{return D::fmadd_d(3.14, numeric_limits<double>::infinity(),1.414);},
-        "fmadd.d, infinity");
-    expect<double>(-numeric_limits<double>::infinity(),
-        []{return D::fmadd_d(3.14,-numeric_limits<double>::infinity(),1.414);},
-        "fmadd.d, -infinity");
-
-    // FMSUB.D
-    expect<double>(D::number(0x400d5A1773A85E43ULL),
-        []{return D::fmsub_d(3.1415926, 1.61803398875, 1.41421356237);},
-        "fmsub.d");
-    expect<bool>(true, []{
-            double fd = D::fmsub_d(3.14, numeric_limits<double>::quiet_NaN(),
-                    1.414);
-            return D::isquietnan(fd);
-        }, "fmsub.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fmsub_d(3.14, 1.816,
-                    numeric_limits<double>::signaling_NaN());
-            return D::isquietnan(fd);
-        }, "fmsub.d, signaling NaN");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fmsub_d(numeric_limits<double>::infinity(), 1.816,
-                    1.414);},
-            "fmsub.d, infinity");
-    expect<double>(-numeric_limits<double>::infinity(),
-            []{return D::fmsub_d(3.14, -numeric_limits<double>::infinity(),
-                    1.414);},
-            "fmsub.d, -infinity");
-    expect<double>(-numeric_limits<double>::infinity(),
-            []{return D::fmsub_d(3.14, 1.816,
-                    numeric_limits<double>::infinity());},
-            "fmsub.d, subtract infinity");
-
-    // FNMSUB.D
-    expect<double>(D::number(0xC00D5A1773A85E43ULL),
-            []{return D::fnmsub_d(3.1415926, 1.61803398875, 1.41421356237);},
-            "fnmsub.d");
-    expect<bool>(true, []{
-            double fd = D::fnmsub_d(3.14, 1.816,
-                    numeric_limits<double>::quiet_NaN());
-            return D::isquietnan(fd);
-        }, "fnmsub.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fnmsub_d(numeric_limits<double>::signaling_NaN(),
-                    1.816, 1.414);
-            return D::isquietnan(fd);
-        }, "fnmsub.d, signaling NaN");
-    expect<double>(-numeric_limits<double>::infinity(),
-            []{return D::fnmsub_d(numeric_limits<double>::infinity(), 1.816,
-                    1.414);},
-            "fnmsub.d, infinity");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fnmsub_d(3.14, -numeric_limits<double>::infinity(),
-                    1.414);},
-            "fnmsub.d, -infinity");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fnmsub_d(3.14, 1.816,
-                    numeric_limits<double>::infinity());},
-            "fnmsub.d, subtract infinity");
-
-    // FNMADD.D
-    expect<double>(D::number(0xC019FD5AED13B1CEULL),
-            []{return D::fnmadd_d(3.1415926, 1.61803398875, 1.41421356237);},
-            "fnmadd.d");
-    expect<bool>(true, []{
-            double fd = D::fnmadd_d(numeric_limits<double>::quiet_NaN(), 3.14,
-                    1.816);
-            return D::isquietnan(fd);
-        }, "fnmadd.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fnmadd_d(3.14,
-                    numeric_limits<double>::signaling_NaN(), 1.816);
-            return D::isquietnan(fd);
-        }, "fnmadd.d, signaling NaN");
-    expect<double>(-numeric_limits<double>::infinity(),
-            []{return D::fnmadd_d(3.14, numeric_limits<double>::infinity(),
-                    1.414);},
-            "fnmadd.d, infinity");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fnmadd_d(3.14, -numeric_limits<double>::infinity(),
-                    1.414);},
-            "fnmadd.d, -infinity");
-
-    // FADD.D
-    expect<double>(D::number(0x4012392540292D7CULL),
-            []{return D::fadd_d(3.1415926, 1.41421356237);}, "fadd.d");
-    expect<bool>(true, []{
-            double fd = D::fadd_d(numeric_limits<double>::quiet_NaN(), 1.414);
-            return D::isquietnan(fd);
-        }, "fadd.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fadd_d(3.14,
-                    numeric_limits<double>::signaling_NaN());
-            return D::isquietnan(fd);
-        }, "fadd.d, signaling NaN");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fadd_d(3.14, numeric_limits<double>::infinity());},
-            "fadd.d, infinity");
-    expect<double>(-numeric_limits<double>::infinity(),
-            []{return D::fadd_d(-numeric_limits<double>::infinity(), 1.816);},
-            "fadd.d, -infinity");
-
-    // FSUB.D
-    expect<double>(D::number(0xBFFBA35833AB7AAEULL),
-            []{return D::fsub_d(1.4142135623, 3.1415926);}, "fsub.d");
-    expect<bool>(true, []{
-            double fd = D::fsub_d(numeric_limits<double>::quiet_NaN(), 1.414);
-            return D::isquietnan(fd);
-        }, "fsub.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fsub_d(3.14,
-                    numeric_limits<double>::signaling_NaN());
-            return D::isquietnan(fd);
-        }, "fsub.d, signaling NaN");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fsub_d(numeric_limits<double>::infinity(), 3.14);},
-            "fsub.d, infinity");
-    expect<double>(-numeric_limits<double>::infinity(),
-            []{return D::fsub_d(-numeric_limits<double>::infinity(), 3.14);},
-            "fsub.d, -infinity");
-    expect<double>(-numeric_limits<double>::infinity(),
-            []{return D::fsub_d(1.414, numeric_limits<double>::infinity());},
-            "fsub.d, subtract infinity");
-
-    // FMUL.D
-    expect<double>(D::number(0x40024E53B708ED9AULL),
-            []{return D::fmul_d(1.61803398875, 1.4142135623);}, "fmul.d");
-    expect<bool>(true, []{
-            double fd = D::fmul_d(numeric_limits<double>::quiet_NaN(), 1.414);
-            return D::isquietnan(fd);
-        }, "fmul.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fmul_d(1.816,
-                    numeric_limits<double>::signaling_NaN());
-            return D::isquietnan(fd);
-        }, "fmul.d, signaling NaN");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fmul_d(numeric_limits<double>::infinity(), 2.718);},
-            "fmul.d, infinity");
-    expect<double>(-numeric_limits<double>::infinity(),
-            []{return D::fmul_d(2.5966, -numeric_limits<double>::infinity());},
-            "fmul.d, -infinity");
-    expect<bool>(true, []{
-            double fd = D::fmul_d(0.0, numeric_limits<double>::infinity());
-            return D::isquietnan(fd);
-        }, "fmul.d, 0*infinity");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fmul_d(numeric_limits<double>::max(), 2.0);},
-            "fmul.d, overflow");
-    expect<double>(0.0,
-            []{return D::fmul_d(numeric_limits<double>::min(),
-                    numeric_limits<double>::min());},
-            "fmul.d, underflow");
-
-    // FDIV.D
-    expect<double>(2.5, []{return D::fdiv_d(10.0, 4.0);}, "fdiv.d");
-    expect<bool>(true, []{
-            double fd = D::fdiv_d(numeric_limits<double>::quiet_NaN(), 4.0);
-            return D::isquietnan(fd);
-        }, "fdiv.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fdiv_d(10.0,
-                    numeric_limits<double>::signaling_NaN());
-            return D::isquietnan(fd);
-        }, "fdiv.d, signaling NaN");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fdiv_d(10.0, 0.0);}, "fdiv.d/0");
-    expect<double>(0.0,
-            []{return D::fdiv_d(10.0, numeric_limits<double>::infinity());},
-            "fdiv.d/infinity");
-    expect<bool>(true, []{
-            double fd = D::fdiv_d(numeric_limits<double>::infinity(),
-                    numeric_limits<double>::infinity());
-            return D::isquietnan(fd);
-        }, "fdiv.d, infinity/infinity");
-    expect<bool>(true, []{
-            double fd = D::fdiv_d(0.0, 0.0);
-            return D::isquietnan(fd);
-        }, "fdiv.d, 0/0");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fdiv_d(numeric_limits<double>::infinity(), 0.0);},
-            "fdiv.d, infinity/0");
-    expect<double>(0.0,
-            []{return D::fdiv_d(0.0, numeric_limits<double>::infinity());},
-            "fdiv.d, 0/infinity");
-    expect<double>(0.0,
-            []{return D::fdiv_d(numeric_limits<double>::min(),
-                    numeric_limits<double>::max());},
-            "fdiv.d, underflow");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fdiv_d(numeric_limits<double>::max(),
-                    numeric_limits<double>::min());},
-            "fdiv.d, overflow");
-
-    // FSQRT.D
-    expect<double>(1e154, []{return D::fsqrt_d(1e308);}, "fsqrt.d");
-    expect<bool>(true, []{
-            double fd = D::fsqrt_d(-1.0);
-            return D::isquietnan(fd);
-        }, "fsqrt.d, NaN");
-    expect<bool>(true, []{
-            double fd = D::fsqrt_d(numeric_limits<double>::quiet_NaN());
-            return D::isquietnan(fd);
-        }, "fsqrt.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fsqrt_d(numeric_limits<double>::signaling_NaN());
-            return D::isquietnan(fd);
-        }, "fsqrt.d, signaling NaN");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fsqrt_d(numeric_limits<double>::infinity());},
-            "fsqrt.d, infinity");
-
-    // FSGNJ.D
-    expect<double>(1.0, []{return D::fsgnj_d(1.0, 25.0);}, "fsgnj.d, ++");
-    expect<double>(-1.0, []{return D::fsgnj_d(1.0, -25.0);}, "fsgnj.d, +-");
-    expect<double>(1.0, []{return D::fsgnj_d(-1.0, 25.0);}, "fsgnj.d, -+");
-    expect<double>(-1.0, []{return D::fsgnj_d(-1.0, -25.0);}, "fsgnj.d, --");
-    expect<bool>(true, []{
-            double fd = D::fsgnj_d(numeric_limits<double>::quiet_NaN(), -4.0);
-            return D::isquietnan(fd);
-        }, "fsgnj.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fsgnj_d(numeric_limits<double>::signaling_NaN(),
-                    -4.0);
-            return D::issignalingnan(fd);
-        }, "fsgnj.d, signaling NaN");
-    expect<double>(4.0,
-            []{return D::fsgnj_d(4.0, numeric_limits<double>::quiet_NaN());},
-            "fsgnj.d, inject NaN");
-    expect<double>(-4.0,
-            []{return D::fsgnj_d(4.0, -numeric_limits<double>::quiet_NaN());},
-            "fsgnj.d, inject -NaN");
-
-    // FSGNJN.D
-    expect<double>(-1.0, []{return D::fsgnjn_d(1.0, 25.0);}, "fsgnjn.d, ++");
-    expect<double>(1.0, []{return D::fsgnjn_d(1.0, -25.0);}, "fsgnjn.d, +-");
-    expect<double>(-1.0, []{return D::fsgnjn_d(-1.0, 25.0);}, "fsgnjn.d, -+");
-    expect<double>(1.0, []{return D::fsgnjn_d(-1.0, -25.0);}, "fsgnjn.d, --");
-    expect<bool>(true, []{
-            double fd = D::fsgnjn_d(numeric_limits<double>::quiet_NaN(), -4.0);
-            return D::isquietnan(fd);
-        }, "fsgnjn.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fsgnjn_d(numeric_limits<double>::signaling_NaN(),
-                    -4.0);
-            return D::issignalingnan(fd);
-        }, "fsgnjn.d, signaling NaN");
-    expect<double>(-4.0,
-            []{return D::fsgnjn_d(4.0, numeric_limits<double>::quiet_NaN());},
-            "fsgnjn.d, inject NaN");
-    expect<double>(4.0,
-            []{return D::fsgnjn_d(4.0, -numeric_limits<double>::quiet_NaN());},
-            "fsgnjn.d, inject NaN");
-
-    // FSGNJX.D
-    expect<double>(1.0, []{return D::fsgnjx_d(1.0, 25.0);}, "fsgnjx.d, ++");
-    expect<double>(-1.0, []{return D::fsgnjx_d(1.0, -25.0);}, "fsgnjx.d, +-");
-    expect<double>(-1.0, []{return D::fsgnjx_d(-1.0, 25.0);}, "fsgnjx.d, -+");
-    expect<double>(1.0, []{return D::fsgnjx_d(-1.0, -25.0);}, "fsgnjx.d, --");
-    expect<bool>(true, []{
-            double fd = D::fsgnjx_d(numeric_limits<double>::quiet_NaN(), -4.0);
-            return D::isquietnan(fd);
-        }, "fsgnjx.d, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fsgnjx_d(numeric_limits<double>::signaling_NaN(),
-                    -4.0);
-            return D::issignalingnan(fd);
-        }, "fsgnjx.d, signaling NaN");
-    expect<double>(4.0,
-            []{return D::fsgnjx_d(4.0, numeric_limits<double>::quiet_NaN());},
-            "fsgnjx.d, inject NaN");
-    expect<double>(-4.0,
-            []{return D::fsgnjx_d(4.0, -numeric_limits<double>::quiet_NaN());},
-            "fsgnjx.d, inject NaN");
-
-    // FMIN.D
-    expect<double>(2.718, []{return D::fmin_d(3.14, 2.718);}, "fmin.d");
-    expect<double>(-numeric_limits<double>::infinity(),
-            []{return D::fmin_d(-numeric_limits<double>::infinity(),
-                    numeric_limits<double>::min());},
-            "fmin.d, -infinity");
-    expect<double>(numeric_limits<double>::max(),
-            []{return D::fmin_d(numeric_limits<double>::infinity(),
-                    numeric_limits<double>::max());},
-            "fmin.d, infinity");
-    expect<double>(-1.414,
-            []{return D::fmin_d(numeric_limits<double>::quiet_NaN(), -1.414);},
-            "fmin.d, quiet NaN first");
-    expect<double>(2.718,
-            []{return D::fmin_d(2.718, numeric_limits<double>::quiet_NaN());},
-            "fmin.d, quiet NaN second");
-    expect<bool>(true, []{
-            double fd = D::fmin_d(numeric_limits<double>::quiet_NaN(),
-                    numeric_limits<double>::quiet_NaN());
-            return D::isquietnan(fd);
-        }, "fmin.d, quiet NaN both");
-    expect<double>(3.14,
-            []{return D::fmin_d(numeric_limits<double>::signaling_NaN(),
-                    3.14);},
-            "fmin.d, signaling NaN first");
-    expect<double>(1.816,
-            []{return D::fmin_d(1.816,
-                    numeric_limits<double>::signaling_NaN());},
-            "fmin.d, signaling NaN second");
-    expect<bool>(true, []{
-            double fd = D::fmin_d(numeric_limits<double>::signaling_NaN(),
-                    numeric_limits<double>::signaling_NaN());
-            return D::issignalingnan(fd);
-        }, "fmin.d, signaling NaN both");
-
-    // FMAX.D
-    expect<double>(3.14, []{return D::fmax_d(3.14, 2.718);}, "fmax.d");
-    expect<double>(numeric_limits<double>::min(),
-            []{return D::fmax_d(-numeric_limits<double>::infinity(),
-                    numeric_limits<double>::min());},
-            "fmax.d, -infinity");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fmax_d(numeric_limits<double>::infinity(),
-                    numeric_limits<double>::max());},
-            "fmax.d, infinity");
-    expect<double>(-1.414,
-            []{return D::fmax_d(numeric_limits<double>::quiet_NaN(), -1.414);},
-            "fmax.d, quiet NaN first");
-    expect<double>(2.718,
-            []{return D::fmax_d(2.718, numeric_limits<double>::quiet_NaN());},
-            "fmax.d, quiet NaN second");
-    expect<bool>(true, []{
-            double fd = D::fmax_d(numeric_limits<double>::quiet_NaN(),
-                    numeric_limits<double>::quiet_NaN());
-            return D::isquietnan(fd);
-        }, "fmax.d, quiet NaN both");
-    expect<double>(3.14,
-            []{return D::fmax_d(numeric_limits<double>::signaling_NaN(),
-                    3.14);},
-            "fmax.d, signaling NaN first");
-    expect<double>(1.816,
-            []{return D::fmax_d(1.816,
-                    numeric_limits<double>::signaling_NaN());},
-            "fmax.d, signaling NaN second");
-    expect<bool>(true, []{
-            double fd = D::fmax_d(numeric_limits<double>::signaling_NaN(),
-                    numeric_limits<double>::signaling_NaN());
-            return D::issignalingnan(fd);
-        }, "fmax.d, signaling NaN both");
-
-    // FCVT.S.D
-    expect<float>(4.0, []{return D::fcvt_s_d(4.0);}, "fcvt.s.d");
-    expect<bool>(true, []{
-            float fd = D::fcvt_s_d(numeric_limits<double>::quiet_NaN());
-            return F::isquietnan(fd);
-        }, "fcvt.s.d, quiet NaN");
-    expect<bool>(true, []{
-            float fd = D::fcvt_s_d(numeric_limits<double>::signaling_NaN());
-            return F::isquietnan(fd);
-        }, "fcvt.s.d, signaling NaN");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return D::fcvt_s_d(numeric_limits<double>::infinity());},
-            "fcvt.s.d, infinity");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return D::fcvt_s_d(numeric_limits<double>::max());},
-            "fcvt.s.d, overflow");
-    expect<float>(0.0, []{return D::fcvt_s_d(numeric_limits<double>::min());},
-            "fcvt.s.d, underflow");
-
-    // FCVT.D.S
-    expect<double>(D::number(0x4005BE76C0000000),
-            []{return D::fcvt_d_s(2.718);}, "fcvt.d.s");
-    expect<bool>(true, []{
-            double fd = D::fcvt_d_s(numeric_limits<float>::quiet_NaN());
-            return D::isquietnan(fd);
-        }, "fcvt.d.s, quiet NaN");
-    expect<bool>(true, []{
-            double fd = D::fcvt_d_s(numeric_limits<float>::signaling_NaN());
-            return D::isquietnan(fd);
-        }, "fcvt.d.s, signaling NaN");
-    expect<double>(numeric_limits<double>::infinity(),
-            []{return D::fcvt_d_s(numeric_limits<float>::infinity());},
-            "fcvt.d.s, infinity");
-
-    // FEQ.D
-    expect<bool>(true, []{return D::feq_d(1.414, 1.414);}, "feq.d, equal");
-    expect<bool>(false,[]{return D::feq_d(2.718, 1.816);}, "feq.d, not equal");
-    expect<bool>(true, []{return D::feq_d(0.0, -0.0);}, "feq.d, 0 == -0");
-    expect<bool>(false,
-            []{return D::feq_d(numeric_limits<double>::quiet_NaN(), -1.0);},
-            "feq.d, quiet NaN first");
-    expect<bool>(false,
-            []{return D::feq_d(2.0, numeric_limits<double>::quiet_NaN());},
-            "feq.d, quiet NaN second");
-    expect<bool>(false,
-            []{return D::feq_d(numeric_limits<double>::quiet_NaN(),
-                    numeric_limits<double>::quiet_NaN());},
-            "feq.d, quiet NaN both");
-    expect<bool>(false,
-            []{return D::feq_d(numeric_limits<double>::signaling_NaN(),-1.0);},
-            "feq.d, signaling NaN first");
-    expect<bool>(false,
-            []{return D::feq_d(2.0, numeric_limits<double>::signaling_NaN());},
-            "feq.d, signaling NaN second");
-    expect<bool>(false,
-            []{return D::feq_d(numeric_limits<double>::signaling_NaN(),
-                    numeric_limits<double>::signaling_NaN());},
-            "feq.d, signaling NaN both");
-
-    // FLT.D
-    expect<bool>(false, []{return D::flt_d(1.414, 1.414);}, "flt.d, equal");
-    expect<bool>(true, []{return D::flt_d(1.816, 2.718);}, "flt.d, less");
-    expect<bool>(false, []{return D::flt_d(2.718, 1.816);}, "flt.d, greater");
-    expect<bool>(false,
-            []{return D::flt_d(numeric_limits<double>::quiet_NaN(), -1.0);},
-            "flt.d, quiet NaN first");
-    expect<bool>(false,
-            []{return D::flt_d(2.0, numeric_limits<double>::quiet_NaN());},
-            "flt.d, quiet NaN second");
-    expect<bool>(false,
-            []{return D::flt_d(numeric_limits<double>::quiet_NaN(),
-                    numeric_limits<double>::quiet_NaN());},
-            "flt.d, quiet NaN both");
-    expect<bool>(false,
-            []{return D::flt_d(numeric_limits<double>::signaling_NaN(),-1.0);},
-            "flt.d, signaling NaN first");
-    expect<bool>(false,
-            []{return D::flt_d(2.0, numeric_limits<double>::signaling_NaN());},
-            "flt.d, signaling NaN second");
-    expect<bool>(false,
-            []{return D::flt_d(numeric_limits<double>::signaling_NaN(),
-                    numeric_limits<double>::signaling_NaN());},
-            "flt.d, signaling NaN both");
-
-    // FLE.D
-    expect<bool>(true, []{return D::fle_d(1.414, 1.414);}, "fle.d, equal");
-    expect<bool>(true, []{return D::fle_d(1.816, 2.718);}, "fle.d, less");
-    expect<bool>(false, []{return D::fle_d(2.718, 1.816);}, "fle.d, greater");
-    expect<bool>(true, []{return D::fle_d(0.0, -0.0);}, "fle.d, 0 == -0");
-    expect<bool>(false,
-            []{return D::fle_d(numeric_limits<double>::quiet_NaN(), -1.0);},
-            "fle.d, quiet NaN first");
-    expect<bool>(false,
-            []{return D::fle_d(2.0, numeric_limits<double>::quiet_NaN());},
-            "fle.d, quiet NaN second");
-    expect<bool>(false,
-            []{return D::fle_d(numeric_limits<double>::quiet_NaN(),
-                    numeric_limits<double>::quiet_NaN());},
-            "fle.d, quiet NaN both");
-    expect<bool>(false,
-            []{return D::fle_d(numeric_limits<double>::signaling_NaN(),-1.0);},
-            "fle.d, signaling NaN first");
-    expect<bool>(false,
-            []{return D::fle_d(2.0, numeric_limits<double>::signaling_NaN());},
-            "fle.d, signaling NaN second");
-    expect<bool>(false,
-            []{return D::fle_d(numeric_limits<double>::signaling_NaN(),
-                    numeric_limits<double>::signaling_NaN());},
-            "fle.d, signaling NaN both");
-
-    // FCLASS.D
-    expect<uint64_t>(0x1,
-            []{return D::fclass_d(-numeric_limits<double>::infinity());},
-            "fclass.d, -infinity");
-    expect<uint64_t>(0x2,
-            []{return D::fclass_d(-3.14);}, "fclass.d, -normal");
-    expect<uint64_t>(0x4,
-            []{return D::fclass_d(D::number(0x800FFFFFFFFFFFFFULL));},
-            "fclass.d, -subnormal");
-    expect<uint64_t>(0x8, []{return D::fclass_d(-0.0);}, "fclass.d, -0.0");
-    expect<uint64_t>(0x10, []{return D::fclass_d(0.0);}, "fclass.d, 0.0");
-    expect<uint64_t>(0x20,
-            []{return D::fclass_d(D::number(0x000FFFFFFFFFFFFFULL));},
-            "fclass.d, subnormal");
-    expect<uint64_t>(0x40, []{return D::fclass_d(1.816);}, "fclass.d, normal");
-    expect<uint64_t>(0x80,
-            []{return D::fclass_d(numeric_limits<double>::infinity());},
-            "fclass.d, infinity");
-    expect<uint64_t>(0x100,
-            []{return D::fclass_d(numeric_limits<double>::signaling_NaN());},
-            "fclass.d, signaling NaN");
-    expect<uint64_t>(0x200,
-            []{return D::fclass_d(numeric_limits<double>::quiet_NaN());},
-            "fclass.s, quiet NaN");
-
-    // FCVT.W.D
-    expect<int64_t>(256, []{return D::fcvt_w_d(256.3);},
-            "fcvt.w.d, truncate positive");
-    expect<int64_t>(-256, []{return D::fcvt_w_d(-256.2);},
-            "fcvt.w.d, truncate negative");
-    expect<int64_t>(0, []{return D::fcvt_w_d(0.0);}, "fcvt.w.d, 0.0");
-    expect<int64_t>(0, []{return D::fcvt_w_d(-0.0);}, "fcvt.w.d, -0.0");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return D::fcvt_w_d(numeric_limits<double>::max());},
-            "fcvt.w.d, overflow");
-    expect<int64_t>(0, []{return D::fcvt_w_d(numeric_limits<double>::min());},
-            "fcvt.w.d, underflow");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return D::fcvt_w_d(numeric_limits<double>::infinity());},
-            "fcvt.w.d, infinity");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return D::fcvt_w_d(-numeric_limits<double>::infinity());},
-            "fcvt.w.d, -infinity");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return D::fcvt_w_d(numeric_limits<double>::quiet_NaN());},
-            "fcvt.w.d, quiet NaN");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return D::fcvt_w_d(-numeric_limits<double>::quiet_NaN());},
-            "fcvt.w.d, quiet -NaN");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return D::fcvt_w_d(numeric_limits<double>::signaling_NaN());},
-            "fcvt.w.d, signaling NaN");
-
-    // FCVT.WU.D
-    expect<uint64_t>(256, []{return D::fcvt_wu_d(256.3);},
-            "fcvt.wu.d, truncate positive");
-    expect<uint64_t>(0, []{return D::fcvt_wu_d(-256.2);},
-            "fcvt.wu.d, truncate negative");
-    expect<uint64_t>(0, []{return D::fcvt_wu_d(0.0);}, "fcvt.wu.d, 0.0");
-    expect<uint64_t>(0, []{return D::fcvt_wu_d(-0.0);}, "fcvt.wu.d, -0.0");
-    expect<uint64_t>(numeric_limits<uint64_t>::max(),
-            []{return D::fcvt_wu_d(numeric_limits<double>::max());},
-            "fcvt.wu.d, overflow");
-    expect<uint64_t>(0,[]{return D::fcvt_wu_d(numeric_limits<double>::min());},
-            "fcvt.wu.d, underflow");
-    expect<uint64_t>(numeric_limits<uint64_t>::max(),
-            []{return D::fcvt_wu_d(numeric_limits<double>::infinity());},
-            "fcvt.wu.d, infinity");
-    expect<uint64_t>(0,
-            []{return D::fcvt_wu_d(-numeric_limits<double>::infinity());},
-            "fcvt.wu.d, -infinity");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return D::fcvt_wu_d(numeric_limits<double>::quiet_NaN());},
-            "fcvt.wu.d, quiet NaN");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return D::fcvt_wu_d(-numeric_limits<double>::quiet_NaN());},
-            "fcvt.wu.d, quiet -NaN");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return D::fcvt_wu_d(numeric_limits<double>::signaling_NaN());},
-            "fcvt.wu.d, signaling NaN");
-
-    // FCVT.D.W
-    expect<double>(0.0, []{return D::fcvt_d_w(0);}, "fcvt.d.w, 0");
-    expect<double>(-2147483648.0,
-            []{return D::fcvt_d_w(numeric_limits<int32_t>::min());},
-            "fcvt.d.w, negative");
-    expect<double>(255.0, []{return D::fcvt_d_w(0xFFFFFFFF000000FFLL);},
-            "fcvt.d.w, truncate");
-
-    // FCVT.D.WU
-    expect<double>(0.0, []{return D::fcvt_d_wu(0);}, "fcvt.d.wu, 0");
-    expect<double>(2147483648.0,
-            []{return D::fcvt_d_wu(numeric_limits<int32_t>::min());},
-            "fcvt.d.wu");
-    expect<double>(255.0,
-            []{return D::fcvt_d_wu(0xFFFFFFFF000000FFLL);},
-            "fcvt.d.wu, truncate");
-
-    // FCVT.L.D
-    expect<int64_t>(256, []{return D::fcvt_l_d(256.3);},
-            "fcvt.l.d, truncate positive");
-    expect<int64_t>(-256, []{return D::fcvt_l_d(-256.2);},
-            "fcvt.l.d, truncate negative");
-    expect<int64_t>(0, []{return D::fcvt_l_d(0.0);}, "fcvt.l.d, 0.0");
-    expect<int64_t>(0, []{return D::fcvt_l_d(-0.0);}, "fcvt.l.d, -0.0");
-    expect<int64_t>(-8589934592LL, []{return D::fcvt_l_d(-8589934592.0);},
-            "fcvt.l.d, 32-bit overflow");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return D::fcvt_l_d(numeric_limits<double>::max());},
-            "fcvt.l.d, overflow");
-    expect<int64_t>(0, []{return D::fcvt_l_d(numeric_limits<double>::min());},
-            "fcvt.l.d, underflow");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return D::fcvt_l_d(numeric_limits<double>::infinity());},
-            "fcvt.l.d, infinity");
-    expect<int64_t>(numeric_limits<int64_t>::min(),
-            []{return D::fcvt_l_d(-numeric_limits<double>::infinity());},
-            "fcvt.l.d, -infinity");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return D::fcvt_l_d(numeric_limits<double>::quiet_NaN());},
-            "fcvt.l.d, quiet NaN");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return D::fcvt_l_d(-numeric_limits<double>::quiet_NaN());},
-            "fcvt.l.d, quiet -NaN");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return D::fcvt_l_d(numeric_limits<double>::signaling_NaN());},
-            "fcvt.l.d, signaling NaN");
-
-    // FCVT.LU.D
-    expect<uint64_t>(256, []{return D::fcvt_lu_d(256.3);},
-            "fcvt.lu.d, truncate positive");
-    expect<uint64_t>(0, []{return D::fcvt_lu_d(-256.2);},
-            "fcvt.lu.d, truncate negative");
-    expect<uint64_t>(0, []{return D::fcvt_lu_d(0.0);}, "fcvt.lu.d, 0.0");
-    expect<uint64_t>(0, []{return D::fcvt_lu_d(-0.0);}, "fcvt.lu.d, -0.0");
-    expect<uint64_t>(8589934592LL, []{return D::fcvt_lu_d(8589934592.0);},
-            "fcvt.lu.d, 32-bit overflow");
-    expect<uint64_t>(numeric_limits<uint64_t>::max(),
-            []{return D::fcvt_lu_d(numeric_limits<double>::max());},
-            "fcvt.lu.d, overflow");
-    expect<uint64_t>(0,[]{return D::fcvt_lu_d(numeric_limits<double>::min());},
-            "fcvt.lu.d, underflow");
-    expect<uint64_t>(numeric_limits<uint64_t>::max(),
-            []{return D::fcvt_lu_d(numeric_limits<double>::infinity());},
-            "fcvt.lu.d, infinity");
-    expect<uint64_t>(0,
-            []{return D::fcvt_lu_d(-numeric_limits<double>::infinity());},
-            "fcvt.lu.d, -infinity");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return D::fcvt_lu_d(numeric_limits<double>::quiet_NaN());},
-            "fcvt.lu.d, quiet NaN");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return D::fcvt_lu_d(-numeric_limits<double>::quiet_NaN());},
-            "fcvt.lu.d, quiet -NaN");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return D::fcvt_lu_d(numeric_limits<double>::signaling_NaN());},
-            "fcvt.lu.d, signaling NaN");
-
-    // FMV.X.D
-    expect<uint64_t>(0x40091EB851EB851FULL, []{return D::fmv_x_d(3.14);},
-            "fmv.x.d, positive");
-    expect<uint64_t>(0xC0091EB851EB851FULL, []{return D::fmv_x_d(-3.14);},
-            "fmv.x.d, negative");
-    expect<uint64_t>(0x0000000000000000ULL, []{return D::fmv_x_d(0.0);},
-            "fmv.x.d, 0.0");
-    expect<uint64_t>(0x8000000000000000ULL, []{return D::fmv_x_d(-0.0);},
-            "fmv.x.d, -0.0");
-
-    // FCVT.D.L
-    expect<double>(0.0, []{return D::fcvt_d_l(0);}, "fcvt.d.l, 0");
-    expect<double>(D::number(0xC3E0000000000000),
-            []{return D::fcvt_d_l(numeric_limits<int64_t>::min());},
-            "fcvt.d.l, negative");
-    expect<double>(D::number(0xC1EFFFFFE0200000),
-            []{return D::fcvt_d_l(0xFFFFFFFF000000FFLL);},
-            "fcvt.d.l, 32-bit truncate");
-
-    // FCVT.D.LU
-    expect<double>(0.0, []{return D::fcvt_d_lu(0);}, "fcvt.d.lu, 0");
-    expect<double>(D::number(0x43E0000000000000),
-            []{return D::fcvt_d_lu(numeric_limits<int64_t>::min());},
-            "fcvt.d.lu");
-    expect<double>(D::number(0x43EFFFFFFFE00000),
-            []{return D::fcvt_d_lu(0xFFFFFFFF000000FFLL);},
-            "fcvt.d.lu, 32-bit truncate");
-
-    // FMV.D.X
-    expect<double>(-numeric_limits<float>::infinity(),
-            []{return D::fmv_d_x(0xFFF0000000000000ULL);}, "fmv.d.x");
-
-    return 0;
-}
diff --git a/src/insttest/rv64d.h b/src/insttest/rv64d.h
deleted file mode 100644
index d2c5898..0000000
--- a/src/insttest/rv64d.h
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#pragma once
-
-#include <cstdint>
-#include <limits>
-
-#include "insttest.h"
-
-namespace D
-{
-
-constexpr inline uint64_t
-bits(double d)
-{
-    return reinterpret_cast<uint64_t&>(d);
-}
-
-constexpr inline double
-number(uint64_t b)
-{
-    return reinterpret_cast<double&>(b);
-}
-
-inline bool
-isquietnan(double f)
-{
-    return std::isnan(f) && (bits(f)&0x0008000000000000ULL) != 0;
-}
-
-inline bool
-issignalingnan(double f)
-{
-    return std::isnan(f) && (bits(f)&0x0008000000000000ULL) == 0;
-}
-
-inline double
-load(double mem)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    asm volatile("fld %0,%1"
-        : "=f" (fd)
-        : "m" (mem));
-    return fd;
-}
-
-inline double
-store(double fs)
-{
-    double mem = std::numeric_limits<double>::signaling_NaN();
-    asm volatile("fsd %1,%0" : "=m" (mem) : "f" (fs));
-    return mem;
-}
-
-inline double
-fmadd_d(double fs1, double fs2, double fs3)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FR4OP("fmadd.d", fd, fs1, fs2, fs3);
-    return fd;
-}
-
-inline double
-fmsub_d(double fs1, double fs2, double fs3)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FR4OP("fmsub.d", fd, fs1, fs2, fs3);
-    return fd;
-}
-
-inline double
-fnmsub_d(double fs1, double fs2, double fs3)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FR4OP("fnmsub.d", fd, fs1, fs2, fs3);
-    return fd;
-}
-
-inline double
-fnmadd_d(double fs1, double fs2, double fs3)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FR4OP("fnmadd.d", fd, fs1, fs2, fs3);
-    return fd;
-}
-
-inline double
-fadd_d(double fs1, double fs2)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FROP("fadd.d", fd, fs1, fs2);
-    return fd;
-}
-
-inline double
-fsub_d(double fs1, double fs2)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FROP("fsub.d", fd, fs1, fs2);
-    return fd;
-}
-
-inline double
-fmul_d(double fs1, double fs2)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FROP("fmul.d", fd, fs1, fs2);
-    return fd;
-}
-
-inline double
-fdiv_d(double fs1, double fs2)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FROP("fdiv.d", fd, fs1, fs2);
-    return fd;
-}
-
-inline double
-fsqrt_d(double fs1)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    asm volatile("fsqrt.d %0,%1" : "=f" (fd) : "f" (fs1));
-    return fd;
-}
-
-inline double
-fsgnj_d(double fs1, double fs2)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FROP("fsgnj.d", fd, fs1, fs2);
-    return fd;
-}
-
-inline double
-fsgnjn_d(double fs1, double fs2)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FROP("fsgnjn.d", fd, fs1, fs2);
-    return fd;
-}
-
-inline double
-fsgnjx_d(double fs1, double fs2)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FROP("fsgnjx.d", fd, fs1, fs2);
-    return fd;
-}
-
-inline double
-fmin_d(double fs1, double fs2)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FROP("fmin.d", fd, fs1, fs2);
-    return fd;
-}
-
-inline double
-fmax_d(double fs1, double fs2)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    FROP("fmax.d", fd, fs1, fs2);
-    return fd;
-}
-
-inline float
-fcvt_s_d(double fs1)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    asm volatile("fcvt.s.d %0,%1" : "=f" (fd) : "f" (fs1));
-    return fd;
-}
-
-inline double
-fcvt_d_s(float fs1)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    asm volatile("fcvt.d.s %0,%1" : "=f" (fd) : "f" (fs1));
-    return fd;
-}
-
-inline bool
-feq_d(double fs1, double fs2)
-{
-    bool rd = false;
-    asm volatile("feq.d %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2));
-    return rd;
-}
-
-inline bool
-flt_d(double fs1, double fs2)
-{
-    bool rd = false;
-    asm volatile("flt.d %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2));
-    return rd;
-}
-
-inline bool
-fle_d(double fs1, double fs2)
-{
-    bool rd = false;
-    asm volatile("fle.d %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2));
-    return rd;
-}
-
-inline uint64_t
-fclass_d(double fs1)
-{
-    uint64_t rd = -1;
-    asm volatile("fclass.d %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline int64_t
-fcvt_w_d(double fs1)
-{
-    int64_t rd = 0;
-    asm volatile("fcvt.w.d %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline uint64_t
-fcvt_wu_d(double fs1)
-{
-    uint64_t rd = 0;
-    asm volatile("fcvt.wu.d %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline float
-fcvt_d_w(int64_t rs1)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    asm volatile("fcvt.d.w %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-inline double
-fcvt_d_wu(uint64_t rs1)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    asm volatile("fcvt.d.wu %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-inline int64_t
-fcvt_l_d(double fs1)
-{
-    int64_t rd = 0;
-    asm volatile("fcvt.l.d %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline uint64_t
-fcvt_lu_d(double fs1)
-{
-    uint64_t rd = 0;
-    asm volatile("fcvt.lu.d %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline uint64_t
-fmv_x_d(double fs1)
-{
-    uint64_t rd = 0;
-    asm volatile("fmv.x.d %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline double
-fcvt_d_l(int64_t rs1)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    asm volatile("fcvt.d.l %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-inline double
-fcvt_d_lu(uint64_t rs1)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    asm volatile("fcvt.d.lu %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-inline double
-fmv_d_x(uint64_t rs1)
-{
-    double fd = std::numeric_limits<double>::signaling_NaN();
-    asm volatile("fmv.d.x %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-} // namespace D
diff --git a/src/insttest/rv64f.cpp b/src/insttest/rv64f.cpp
deleted file mode 100644
index f8b79f4..0000000
--- a/src/insttest/rv64f.cpp
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#include <cstdint>
-#include <limits>
-
-#include "insttest.h"
-#include "rv64f.h"
-
-int main()
-{
-    using namespace std;
-    using namespace insttest;
-
-    // FLAGS
-    expect<uint64_t>(0, []{
-            F::fsflags(0);
-            return F::frflags();
-        }, "clear fsflags");
-
-    // Memory
-    expect<float>(3.14, []{return F::load(3.14);}, "flw");
-    expect<float>(1.816, []{return F::store(1.816);}, "fsw");
-
-    // FMADD.S
-    expect<float>(7.11624, []{return F::fmadd_s(3.14, 1.816, 1.414);},
-            "fmadd.s");
-    expect<bool>(true, []{
-            float fd = F::fmadd_s(numeric_limits<float>::quiet_NaN(), 3.14,
-                    1.816);
-            return F::isquietnan(fd);
-        }, "fmadd.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fmadd_s(3.14, numeric_limits<float>::signaling_NaN(),
-                    1.816);
-            return F::isquietnan(fd);
-        }, "fmadd.s, signaling NaN");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fmadd_s(3.14, numeric_limits<float>::infinity(),
-                    1.414);},
-            "fmadd.s, infinity");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fmadd_s(3.14, -numeric_limits<float>::infinity(),
-                    1.414);},
-            "fmadd.s, -infinity");
-
-    // FMSUB.S
-    expect<float>(4.28824, []{return F::fmsub_s(3.14, 1.816, 1.414);},
-            "fmsub.s");
-    expect<bool>(true, []{
-            float fd = F::fmsub_s(3.14, numeric_limits<float>::quiet_NaN(),
-                    1.816);
-            return F::isquietnan(fd);
-        }, "fmsub.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fmsub_s(3.14, 1.816,
-                    numeric_limits<float>::signaling_NaN());
-            return F::isquietnan(fd);
-        }, "fmsub.s, signaling NaN");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fmsub_s(numeric_limits<float>::infinity(), 1.816,
-                    1.414);},
-            "fmsub.s, infinity");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fmsub_s(3.14, -numeric_limits<float>::infinity(),
-                    1.414);},
-            "fmsub.s, -infinity");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fmsub_s(3.14, 1.816,
-                    numeric_limits<float>::infinity());},
-            "fmsub.s, subtract infinity");
-
-    // FNMSUB.S
-    expect<float>(-4.28824, []{return F::fnmsub_s(3.14, 1.816, 1.414);},
-            "fnmsub.s");
-    expect<bool>(true, []{
-            float fd = F::fnmsub_s(3.14, 1.816,
-                    numeric_limits<float>::quiet_NaN());
-            return F::isquietnan(fd);
-        }, "fnmsub.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fnmsub_s(numeric_limits<float>::signaling_NaN(),
-                    1.816, 1.414);
-            return F::isquietnan(fd);
-        }, "fnmsub.s, signaling NaN");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fnmsub_s(numeric_limits<float>::infinity(),
-                    1.816, 1.414);},
-            "fnmsub.s, infinity");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fnmsub_s(3.14, -numeric_limits<float>::infinity(),
-                    1.414);},
-            "fnmsub.s, -infinity");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fnmsub_s(3.14, 1.816,
-                    numeric_limits<float>::infinity());},
-            "fnmsub.s, subtract infinity");
-
-    // FNMADD.S
-    expect<float>(-7.11624, []{return F::fnmadd_s(3.14, 1.816, 1.414);},
-            "fnmadd.s");
-    expect<bool>(true, []{
-            float fd = F::fnmadd_s(numeric_limits<float>::quiet_NaN(), 3.14,
-                    1.816);
-            return F::isquietnan(fd);
-        }, "fnmadd.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fnmadd_s(3.14,numeric_limits<float>::signaling_NaN(),
-                    1.816);
-            return F::isquietnan(fd);
-        }, "fnmadd.s, signaling NaN");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fnmadd_s(3.14, numeric_limits<float>::infinity(),
-                    1.414);},
-            "fnmadd.s, infinity");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fnmadd_s(3.14, -numeric_limits<float>::infinity(),
-                    1.414);},
-            "fnmadd.s, -infinity");
-
-    // FADD.S
-    expect<float>(4.554, []{return F::fadd_s(3.14, 1.414);}, "fadd.s");
-    expect<bool>(true, []{
-            float fd = F::fadd_s(numeric_limits<float>::quiet_NaN(), 1.414);
-            return F::isquietnan(fd);
-        }, "fadd.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fadd_s(3.14, numeric_limits<float>::signaling_NaN());
-            return F::isquietnan(fd);
-        }, "fadd.s, signaling NaN");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fadd_s(3.14, numeric_limits<float>::infinity());},
-            "fadd.s, infinity");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fadd_s(-numeric_limits<float>::infinity(), 1.816);},
-            "fadd.s, -infinity");
-
-    // FSUB.S
-    expect<float>(F::number(0xbfdced92), []{return F::fsub_s(1.414, 3.14);},
-            "fsub.s");
-    expect<bool>(true, []{
-            float fd = F::fsub_s(numeric_limits<float>::quiet_NaN(), 1.414);
-            return F::isquietnan(fd);
-        }, "fsub.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fsub_s(3.14, numeric_limits<float>::signaling_NaN());
-            return F::isquietnan(fd);
-        }, "fsub.s, signaling NaN");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fsub_s(numeric_limits<float>::infinity(), 3.14);},
-            "fsub.s, infinity");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fsub_s(-numeric_limits<float>::infinity(), 3.14);},
-            "fsub.s, -infinity");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fsub_s(1.414, numeric_limits<float>::infinity());},
-            "fsub.s, subtract infinity");
-
-    // FMUL.S
-    expect<float>(F::number(0x4024573b), []{return F::fmul_s(1.816, 1.414);},
-            "fmul.s");
-    expect<bool>(true, []{
-            float fd = F::fmul_s(numeric_limits<float>::quiet_NaN(), 1.414);
-            return F::isquietnan(fd);
-        }, "fmul.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fmul_s(1.816,
-                    numeric_limits<float>::signaling_NaN());
-            return F::isquietnan(fd);
-        }, "fmul.s, signaling NaN");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fmul_s(numeric_limits<float>::infinity(), 2.718);},
-            "fmul.s, infinity");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fmul_s(2.5966, -numeric_limits<float>::infinity());},
-            "fmul.s, -infinity");
-    expect<bool>(true, []{
-            float fd = F::fmul_s(0.0, numeric_limits<float>::infinity());
-            return F::isquietnan(fd);
-        }, "fmul.s, 0*infinity");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fmul_s(numeric_limits<float>::max(), 2.0);},
-            "fmul.s, overflow");
-    expect<float>(0.0,
-            []{return F::fmul_s(numeric_limits<float>::min(),
-                    numeric_limits<float>::min());},
-            "fmul.s, underflow");
-
-    // FDIV.S
-    expect<float>(2.5, []{return F::fdiv_s(10.0, 4.0);}, "fdiv.s");
-    expect<bool>(true, []{
-            float fd = F::fdiv_s(numeric_limits<float>::quiet_NaN(), 4.0);
-            return F::isquietnan(fd);
-        }, "fdiv.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fdiv_s(10.0, numeric_limits<float>::signaling_NaN());
-            return F::isquietnan(fd);
-        }, "fdiv.s, signaling NaN");
-    expect<float>(numeric_limits<float>::infinity(),
-        []{return F::fdiv_s(10.0, 0.0);}, "fdiv.s/0");
-    expect<float>(0.0,
-        []{return F::fdiv_s(10.0, numeric_limits<float>::infinity());},
-        "fdiv.s/infinity");
-    expect<bool>(true, []{
-            float fd = F::fdiv_s(numeric_limits<float>::infinity(),
-                    numeric_limits<float>::infinity());
-            return F::isquietnan(fd);
-            }, "fdiv.s, infinity/infinity");
-    expect<bool>(true, []{
-            float fd = F::fdiv_s(0.0, 0.0);
-            return F::isquietnan(fd);
-        }, "fdiv.s, 0/0");
-    expect<float>(numeric_limits<float>::infinity(),
-        []{return F::fdiv_s(numeric_limits<float>::infinity(), 0.0);},
-        "fdiv.s, infinity/0");
-    expect<float>(0.0,
-        []{return F::fdiv_s(0.0, numeric_limits<float>::infinity());},
-        "fdiv.s, 0/infinity");
-    expect<float>(0.0,
-            []{return F::fdiv_s(numeric_limits<float>::min(),
-                    numeric_limits<float>::max());},
-            "fdiv.s, underflow");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fdiv_s(numeric_limits<float>::max(),
-                    numeric_limits<float>::min());},
-            "fdiv.s, overflow");
-
-    // FSQRT.S
-    expect<float>(0.3, []{return F::fsqrt_s(0.09);}, "fsqrt.s");
-    expect<bool>(true, []{
-            float fd = F::fsqrt_s(-1.0);
-            return F::isquietnan(fd);
-        }, "fsqrt.s, NaN");
-    expect<bool>(true, []{
-            float fd = F::fsqrt_s(numeric_limits<float>::quiet_NaN());
-            return F::isquietnan(fd);
-        }, "fsqrt.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fsqrt_s(numeric_limits<float>::signaling_NaN());
-            return F::isquietnan(fd);
-        }, "fsqrt.s, signaling NaN");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fsqrt_s(numeric_limits<float>::infinity());},
-            "fsqrt.s, infinity");
-
-    // FSGNJ.S
-    expect<float>(1.0, []{return F::fsgnj_s(1.0, 25.0);}, "fsgnj.s, ++");
-    expect<float>(-1.0, []{return F::fsgnj_s(1.0, -25.0);}, "fsgnj.s, +-");
-    expect<float>(1.0, []{return F::fsgnj_s(-1.0, 25.0);}, "fsgnj.s, -+");
-    expect<float>(-1.0, []{return F::fsgnj_s(-1.0, -25.0);}, "fsgnj.s, --");
-    expect<bool>(true, []{
-            float fd = F::fsgnj_s(numeric_limits<float>::quiet_NaN(), -4.0);
-            return F::isquietnan(fd);
-        }, "fsgnj.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fsgnj_s(numeric_limits<float>::signaling_NaN(),
-                    -4.0);
-            return F::issignalingnan(fd);
-        }, "fsgnj.s, signaling NaN");
-    expect<float>(4.0, []{return F::fsgnj_s(4.0,
-                numeric_limits<float>::quiet_NaN());}, "fsgnj.s, inject NaN");
-    expect<float>(-4.0,
-            []{return F::fsgnj_s(4.0, -numeric_limits<float>::quiet_NaN());},
-            "fsgnj.s, inject -NaN");
-
-    // FSGNJN.S
-    expect<float>(-1.0, []{return F::fsgnjn_s(1.0, 25.0);}, "fsgnjn.s, ++");
-    expect<float>(1.0, []{return F::fsgnjn_s(1.0, -25.0);}, "fsgnjn.s, +-");
-    expect<float>(-1.0, []{return F::fsgnjn_s(-1.0, 25.0);}, "fsgnjn.s, -+");
-    expect<float>(1.0, []{return F::fsgnjn_s(-1.0, -25.0);}, "fsgnjn.s, --");
-    expect<bool>(true, []{
-            float fd = F::fsgnjn_s(numeric_limits<float>::quiet_NaN(), -4.0);
-            return F::isquietnan(fd);
-        }, "fsgnjn.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fsgnjn_s(numeric_limits<float>::signaling_NaN(),
-                    -4.0);
-            return F::issignalingnan(fd);
-        }, "fsgnjn.s, signaling NaN");
-    expect<float>(-4.0,
-            []{return F::fsgnjn_s(4.0, numeric_limits<float>::quiet_NaN());},
-            "fsgnjn.s, inject NaN");
-    expect<float>(4.0,
-            []{return F::fsgnjn_s(4.0, -numeric_limits<float>::quiet_NaN());},
-            "fsgnjn.s, inject NaN");
-
-    // FSGNJX.S
-    expect<float>(1.0, []{return F::fsgnjx_s(1.0, 25.0);}, "fsgnjx.s, ++");
-    expect<float>(-1.0, []{return F::fsgnjx_s(1.0, -25.0);}, "fsgnjx.s, +-");
-    expect<float>(-1.0, []{return F::fsgnjx_s(-1.0, 25.0);}, "fsgnjx.s, -+");
-    expect<float>(1.0, []{return F::fsgnjx_s(-1.0, -25.0);}, "fsgnjx.s, --");
-    expect<bool>(true, []{
-            float fd = F::fsgnjx_s(numeric_limits<float>::quiet_NaN(), -4.0);
-            return F::isquietnan(fd);
-        }, "fsgnjx.s, quiet NaN");
-    expect<bool>(true, []{
-            float fd = F::fsgnjx_s(numeric_limits<float>::signaling_NaN(),
-                    -4.0);
-            return F::issignalingnan(fd);
-        }, "fsgnjx.s, signaling NaN");
-    expect<float>(4.0,
-            []{return F::fsgnjx_s(4.0, numeric_limits<float>::quiet_NaN());},
-            "fsgnjx.s, inject NaN");
-    expect<float>(-4.0,
-            []{return F::fsgnjx_s(4.0, -numeric_limits<float>::quiet_NaN());},
-            "fsgnjx.s, inject -NaN");
-
-    // FMIN.S
-    expect<float>(2.718, []{return F::fmin_s(3.14, 2.718);}, "fmin.s");
-    expect<float>(-numeric_limits<float>::infinity(),
-            []{return F::fmin_s(-numeric_limits<float>::infinity(),
-                    numeric_limits<float>::min());},
-            "fmin.s, -infinity");
-    expect<float>(numeric_limits<float>::max(),
-            []{return F::fmin_s(numeric_limits<float>::infinity(),
-                    numeric_limits<float>::max());},
-            "fmin.s, infinity");
-    expect<float>(-1.414,
-            []{return F::fmin_s(numeric_limits<float>::quiet_NaN(), -1.414);},
-            "fmin.s, quiet NaN first");
-    expect<float>(2.718,
-            []{return F::fmin_s(2.718, numeric_limits<float>::quiet_NaN());},
-            "fmin.s, quiet NaN second");
-    expect<bool>(true, []{
-            float fd = F::fmin_s(numeric_limits<float>::quiet_NaN(),
-                    numeric_limits<float>::quiet_NaN());
-            return F::isquietnan(fd);
-        }, "fmin.s, quiet NaN both");
-    expect<float>(3.14,
-            []{return F::fmin_s(numeric_limits<float>::signaling_NaN(),
-                    3.14);},
-            "fmin.s, signaling NaN first");
-    expect<float>(1.816,
-            []{return F::fmin_s(1.816,
-                    numeric_limits<float>::signaling_NaN());},
-            "fmin.s, signaling NaN second");
-    expect<bool>(true, []{
-            float fd = F::fmin_s(numeric_limits<float>::signaling_NaN(),
-                    numeric_limits<float>::signaling_NaN());
-            return F::issignalingnan(fd);
-        }, "fmin.s, signaling NaN both");
-
-    // FMAX.S
-    expect<float>(3.14, []{return F::fmax_s(3.14, 2.718);}, "fmax.s");
-    expect<float>(numeric_limits<float>::min(),
-            []{return F::fmax_s(-numeric_limits<float>::infinity(),
-                    numeric_limits<float>::min());},
-            "fmax.s, -infinity");
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fmax_s(numeric_limits<float>::infinity(),
-                    numeric_limits<float>::max());},
-            "fmax.s, infinity");
-    expect<float>(-1.414,
-            []{return F::fmax_s(numeric_limits<float>::quiet_NaN(), -1.414);},
-            "fmax.s, quiet NaN first");
-    expect<float>(2.718,
-            []{return F::fmax_s(2.718, numeric_limits<float>::quiet_NaN());},
-            "fmax.s, quiet NaN second");
-    expect<bool>(true, []{
-            float fd = F::fmax_s(numeric_limits<float>::quiet_NaN(),
-                    numeric_limits<float>::quiet_NaN());
-            return F::isquietnan(fd);
-        }, "fmax.s, quiet NaN both");
-    expect<float>(3.14,
-            []{return F::fmax_s(numeric_limits<float>::signaling_NaN(),
-                    3.14);},
-            "fmax.s, signaling NaN first");
-    expect<float>(1.816, []{return F::fmax_s(1.816,
-                numeric_limits<float>::signaling_NaN());},
-            "fmax.s, signaling NaN second");
-    expect<bool>(true, []{
-            float fd = F::fmax_s(numeric_limits<float>::signaling_NaN(),
-                    numeric_limits<float>::signaling_NaN());
-            return F::issignalingnan(fd);
-        }, "fmax.s, signaling NaN both");
-
-    // FCVT.W.S
-    expect<int64_t>(256, []{return F::fcvt_w_s(256.3);},
-            "fcvt.w.s, truncate positive");
-    expect<int64_t>(-256, []{return F::fcvt_w_s(-256.2);},
-            "fcvt.w.s, truncate negative");
-    expect<int64_t>(0, []{return F::fcvt_w_s(0.0);}, "fcvt.w.s, 0.0");
-    expect<int64_t>(0, []{return F::fcvt_w_s(-0.0);}, "fcvt.w.s, -0.0");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return F::fcvt_w_s(numeric_limits<float>::max());},
-            "fcvt.w.s, overflow");
-    expect<int64_t>(0, []{return F::fcvt_w_s(numeric_limits<float>::min());},
-            "fcvt.w.s, underflow");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return F::fcvt_w_s(numeric_limits<float>::infinity());},
-            "fcvt.w.s, infinity");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return F::fcvt_w_s(-numeric_limits<float>::infinity());},
-            "fcvt.w.s, -infinity");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return F::fcvt_w_s(numeric_limits<float>::quiet_NaN());},
-            "fcvt.w.s, quiet NaN");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return F::fcvt_w_s(-numeric_limits<float>::quiet_NaN());},
-            "fcvt.w.s, quiet -NaN");
-    expect<int64_t>(numeric_limits<int32_t>::max(),
-            []{return F::fcvt_w_s(numeric_limits<float>::signaling_NaN());},
-            "fcvt.w.s, signaling NaN");
-
-    // FCVT.WU.S
-    expect<uint64_t>(256, []{return F::fcvt_wu_s(256.3);},
-            "fcvt.wu.s, truncate positive");
-    expect<uint64_t>(0, []{return F::fcvt_wu_s(-256.2);},
-            "fcvt.wu.s, truncate negative");
-    expect<uint64_t>(0, []{return F::fcvt_wu_s(0.0);}, "fcvt.wu.s, 0.0");
-    expect<uint64_t>(0, []{return F::fcvt_wu_s(-0.0);}, "fcvt.wu.s, -0.0");
-    expect<uint64_t>(numeric_limits<uint64_t>::max(),
-            []{return F::fcvt_wu_s(numeric_limits<float>::max());},
-            "fcvt.wu.s, overflow");
-    expect<uint64_t>(0, []{return F::fcvt_wu_s(numeric_limits<float>::min());},
-            "fcvt.wu.s, underflow");
-    expect<uint64_t>(numeric_limits<uint64_t>::max(),
-            []{return F::fcvt_wu_s(numeric_limits<float>::infinity());},
-            "fcvt.wu.s, infinity");
-    expect<uint64_t>(0,
-            []{return F::fcvt_wu_s(-numeric_limits<float>::infinity());},
-            "fcvt.wu.s, -infinity");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return F::fcvt_wu_s(numeric_limits<float>::quiet_NaN());},
-            "fcvt.wu.s, quiet NaN");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return F::fcvt_wu_s(-numeric_limits<float>::quiet_NaN());},
-            "fcvt.wu.s, quiet -NaN");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return F::fcvt_wu_s(numeric_limits<float>::signaling_NaN());},
-            "fcvt.wu.s, signaling NaN");
-
-    // FMV.X.S
-    expect<uint64_t>(0x000000004048F5C3ULL, []{return F::fmv_x_s(3.14);},
-            "fmv.x.s, positive");
-    expect<uint64_t>(0xFFFFFFFFC048F5C3ULL, []{return F::fmv_x_s(-3.14);},
-            "fmv.x.s, negative");
-    expect<uint64_t>(0x0000000000000000ULL, []{return F::fmv_x_s(0.0);},
-            "fmv.x.s, 0.0");
-    expect<uint64_t>(0xFFFFFFFF80000000ULL, []{return F::fmv_x_s(-0.0);},
-            "fmv.x.s, -0.0");
-
-    // FEQ.S
-    expect<bool>(true, []{return F::feq_s(1.414, 1.414);}, "feq.s, equal");
-    expect<bool>(false, []{return F::feq_s(2.718, 1.816);},
-            "feq.s, not equal");
-    expect<bool>(true, []{return F::feq_s(0.0, -0.0);}, "feq.s, 0 == -0");
-    expect<bool>(false,
-            []{return F::feq_s(numeric_limits<float>::quiet_NaN(), -1.0);},
-            "feq.s, quiet NaN first");
-    expect<bool>(false,
-            []{return F::feq_s(2.0, numeric_limits<float>::quiet_NaN());},
-            "feq.s, quiet NaN second");
-    expect<bool>(false,
-            []{return F::feq_s(numeric_limits<float>::quiet_NaN(),
-                    numeric_limits<float>::quiet_NaN());},
-            "feq.s, quiet NaN both");
-    expect<bool>(false,
-            []{return F::feq_s(numeric_limits<float>::signaling_NaN(), -1.0);},
-            "feq.s, signaling NaN first");
-    expect<bool>(false,
-            []{return F::feq_s(2.0, numeric_limits<float>::signaling_NaN());},
-            "feq.s, signaling NaN second");
-    expect<bool>(false,
-            []{return F::feq_s(numeric_limits<float>::signaling_NaN(),
-                    numeric_limits<float>::signaling_NaN());},
-            "feq.s, signaling NaN both");
-
-    // FLT.S
-    expect<bool>(false, []{return F::flt_s(1.414, 1.414);}, "flt.s, equal");
-    expect<bool>(true, []{return F::flt_s(1.816, 2.718);}, "flt.s, less");
-    expect<bool>(false, []{return F::flt_s(2.718, 1.816);}, "flt.s, greater");
-    expect<bool>(false,
-            []{return F::flt_s(numeric_limits<float>::quiet_NaN(), -1.0);},
-            "flt.s, quiet NaN first");
-    expect<bool>(false,
-            []{return F::flt_s(2.0, numeric_limits<float>::quiet_NaN());},
-            "flt.s, quiet NaN second");
-    expect<bool>(false,
-            []{return F::flt_s(numeric_limits<float>::quiet_NaN(),
-                    numeric_limits<float>::quiet_NaN());},
-            "flt.s, quiet NaN both");
-    expect<bool>(false,
-            []{return F::flt_s(numeric_limits<float>::signaling_NaN(), -1.0);},
-            "flt.s, signaling NaN first");
-    expect<bool>(false,
-            []{return F::flt_s(2.0, numeric_limits<float>::signaling_NaN());},
-            "flt.s, signaling NaN second");
-    expect<bool>(false,
-            []{return F::flt_s(numeric_limits<float>::signaling_NaN(),
-                    numeric_limits<float>::signaling_NaN());},
-            "flt.s, signaling NaN both");
-
-    // FLE.S
-    expect<bool>(true, []{return F::fle_s(1.414, 1.414);}, "fle.s, equal");
-    expect<bool>(true, []{return F::fle_s(1.816, 2.718);}, "fle.s, less");
-    expect<bool>(false, []{return F::fle_s(2.718, 1.816);}, "fle.s, greater");
-    expect<bool>(true, []{return F::fle_s(0.0, -0.0);}, "fle.s, 0 == -0");
-    expect<bool>(false,
-            []{return F::fle_s(numeric_limits<float>::quiet_NaN(), -1.0);},
-            "fle.s, quiet NaN first");
-    expect<bool>(false,
-            []{return F::fle_s(2.0, numeric_limits<float>::quiet_NaN());},
-            "fle.s, quiet NaN second");
-    expect<bool>(false,
-            []{return F::fle_s(numeric_limits<float>::quiet_NaN(),
-                    numeric_limits<float>::quiet_NaN());},
-            "fle.s, quiet NaN both");
-    expect<bool>(false,
-            []{return F::fle_s(numeric_limits<float>::signaling_NaN(), -1.0);},
-            "fle.s, signaling NaN first");
-    expect<bool>(false,
-            []{return F::fle_s(2.0, numeric_limits<float>::signaling_NaN());},
-            "fle.s, signaling NaN second");
-    expect<bool>(false,
-            []{return F::fle_s(numeric_limits<float>::signaling_NaN(),
-                    numeric_limits<float>::signaling_NaN());},
-            "fle.s, signaling NaN both");
-
-    // FCLASS.S
-    expect<uint64_t>(0x1,
-            []{return F::fclass_s(-numeric_limits<float>::infinity());},
-            "fclass.s, -infinity");
-    expect<uint64_t>(0x2, []{return F::fclass_s(-3.14);}, "fclass.s, -normal");
-    expect<uint64_t>(0x4, []{return F::fclass_s(F::number(0x807FFFFF));},
-            "fclass.s, -subnormal");
-    expect<uint64_t>(0x8, []{return F::fclass_s(-0.0);}, "fclass.s, -0.0");
-    expect<uint64_t>(0x10, []{return F::fclass_s(0.0);}, "fclass.s, 0.0");
-    expect<uint64_t>(0x20, []{return F::fclass_s(F::number(0x007FFFFF));},
-            "fclass.s, subnormal");
-    expect<uint64_t>(0x40, []{return F::fclass_s(1.816);}, "fclass.s, normal");
-    expect<uint64_t>(0x80,
-            []{return F::fclass_s(numeric_limits<float>::infinity());},
-            "fclass.s, infinity");
-    expect<uint64_t>(0x100,
-            []{return F::fclass_s(numeric_limits<float>::signaling_NaN());},
-            "fclass.s, signaling NaN");
-    expect<uint64_t>(0x200,
-            []{return F::fclass_s(numeric_limits<float>::quiet_NaN());},
-            "fclass.s, quiet NaN");
-
-    // FCVT.S.W
-    expect<float>(0.0, []{return F::fcvt_s_w(0);}, "fcvt.s.w, 0");
-    expect<float>(-2147483648.0,
-            []{return F::fcvt_s_w(numeric_limits<int32_t>::min());},
-            "fcvt.s.w, negative");
-    expect<float>(255.0, []{return F::fcvt_s_w(0xFFFFFFFF000000FFLL);},
-            "fcvt.s.w, truncate");
-
-    // FCVT.S.WU
-    expect<float>(0.0, []{return F::fcvt_s_wu(0);}, "fcvt.s.wu, 0");
-    expect<float>(2147483648.0,
-            []{return F::fcvt_s_wu(numeric_limits<int32_t>::min());},
-            "fcvt.s.wu");
-    expect<float>(255.0, []{return F::fcvt_s_wu(0xFFFFFFFF000000FFLL);},
-            "fcvt.s.wu, truncate");
-
-    // FMV.S.X
-    expect<float>(numeric_limits<float>::infinity(),
-            []{return F::fmv_s_x(0x7F800000);}, "fmv.s.x");
-    expect<float>(-0.0, []{return F::fmv_s_x(0xFFFFFFFF80000000ULL);},
-            "fmv.s.x, truncate");
-
-    // FCSR functions
-    int rm = F::frrm();
-    expect<uint64_t>(0x7, []{ // FSRM
-            F::fsrm(-1);
-            return F::frrm();
-        }, "fsrm");
-    expect<uint64_t>(0x1F, []{ // FSFLAGS
-            F::fsflags(0);
-            F::fsflags(-1);
-            return F::frflags();
-        }, "fsflags");
-    expect<uint64_t>(0xFF, []{ // FSCSR
-            F::fsflags(0);
-            F::fsrm(0);
-            F::fscsr(-1);
-            return F::frcsr();
-        }, "fscsr");
-    expect<int>(rm << 5, [=]{
-            F::fscsr(0);
-            F::fsrm(rm);
-            return F::frcsr();
-        }, "restore initial round mode");
-
-    F::fsflags(0);
-
-    // FCVT.L.S
-    expect<int64_t>(256, []{return F::fcvt_l_s(256.3);},
-            "fcvt.l.s, truncate positive");
-    expect<int64_t>(-256, []{return F::fcvt_l_s(-256.2);},
-            "fcvt.l.s, truncate negative");
-    expect<int64_t>(0, []{return F::fcvt_l_s(0.0);}, "fcvt.l.s, 0.0");
-    expect<int64_t>(0, []{return F::fcvt_l_s(-0.0);}, "fcvt.l.s, -0.0");
-    expect<int64_t>(-8589934592LL, []{return F::fcvt_l_s(-8589934592.0);},
-            "fcvt.l.s, 32-bit overflow");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return F::fcvt_l_s(numeric_limits<float>::max());},
-            "fcvt.l.s, overflow");
-    expect<int64_t>(0, []{return F::fcvt_l_s(numeric_limits<float>::min());},
-            "fcvt.l.s, underflow");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return F::fcvt_l_s(numeric_limits<float>::infinity());},
-            "fcvt.l.s, infinity");
-    expect<int64_t>(numeric_limits<int64_t>::min(),
-            []{return F::fcvt_l_s(-numeric_limits<float>::infinity());},
-            "fcvt.l.s, -infinity");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return F::fcvt_l_s(numeric_limits<float>::quiet_NaN());},
-            "fcvt.l.s, quiet NaN");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return F::fcvt_l_s(-numeric_limits<float>::quiet_NaN());},
-            "fcvt.l.s, quiet -NaN");
-    expect<int64_t>(numeric_limits<int64_t>::max(),
-            []{return F::fcvt_l_s(numeric_limits<float>::signaling_NaN());},
-            "fcvt.l.s, signaling NaN");
-
-    // FCVT.LU.S
-    expect<uint64_t>(256, []{return F::fcvt_lu_s(256.3);},
-            "fcvt.lu.s, truncate positive");
-    expect<uint64_t>(0, []{return F::fcvt_lu_s(-256.2);},
-            "fcvt.lu.s, truncate negative");
-    expect<uint64_t>(0, []{return F::fcvt_lu_s(0.0);}, "fcvt.lu.s, 0.0");
-    expect<uint64_t>(0, []{return F::fcvt_lu_s(-0.0);}, "fcvt.lu.s, -0.0");
-    expect<uint64_t>(8589934592LL,
-            []{return F::fcvt_lu_s(8589934592.0);},
-            "fcvt.lu.s, 32-bit overflow");
-    expect<uint64_t>(numeric_limits<uint64_t>::max(),
-            []{return F::fcvt_lu_s(numeric_limits<float>::max());},
-            "fcvt.lu.s, overflow");
-    expect<uint64_t>(0, []{return F::fcvt_lu_s(numeric_limits<float>::min());},
-            "fcvt.lu.s, underflow");
-    expect<uint64_t>(numeric_limits<uint64_t>::max(),
-            []{return F::fcvt_lu_s(numeric_limits<float>::infinity());},
-            "fcvt.lu.s, infinity");
-    expect<uint64_t>(0,
-            []{return F::fcvt_lu_s(-numeric_limits<float>::infinity());},
-            "fcvt.lu.s, -infinity");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return F::fcvt_lu_s(numeric_limits<float>::quiet_NaN());},
-            "fcvt.lu.s, quiet NaN");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return F::fcvt_lu_s(-numeric_limits<float>::quiet_NaN());},
-            "fcvt.lu.s, quiet -NaN");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFFULL,
-            []{return F::fcvt_lu_s(numeric_limits<float>::signaling_NaN());},
-            "fcvt.lu.s, signaling NaN");
-
-    // FCVT.S.L
-    expect<float>(0.0, []{return F::fcvt_s_l(0);}, "fcvt.s.l, 0");
-    expect<float>(-9.223372e18,
-            []{return F::fcvt_s_l(numeric_limits<int64_t>::min());},
-            "fcvt.s.l, negative");
-    expect<float>(-4.29496704e9, []{return F::fcvt_s_l(0xFFFFFFFF000000FFLL);},
-            "fcvt.s.l, 32-bit truncate");
-
-    // FCVT.S.LU
-    expect<float>(0.0, []{return F::fcvt_s_lu(0);}, "fcvt.s.lu, 0");
-    expect<float>(9.223372e18,
-            []{return F::fcvt_s_lu(numeric_limits<int64_t>::min());},
-            "fcvt.s.lu");
-    expect<float>(1.8446744e19, []{return F::fcvt_s_lu(0xFFFFFFFF000000FFLL);},
-            "fcvt.s.lu, 32-bit truncate");
-
-    return 0;
-}
diff --git a/src/insttest/rv64f.h b/src/insttest/rv64f.h
deleted file mode 100644
index 5a6798c..0000000
--- a/src/insttest/rv64f.h
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#pragma once
-
-#include <cstdint>
-#include <limits>
-
-#include "insttest.h"
-
-namespace F
-{
-
-constexpr inline uint32_t
-bits(float f)
-{
-    return reinterpret_cast<uint32_t&>(f);
-}
-
-constexpr inline float
-number(uint32_t b)
-{
-    return reinterpret_cast<float&>(b);
-}
-
-inline bool
-isquietnan(float f)
-{
-    return std::isnan(f) && (bits(f)&0x00400000) != 0;
-}
-
-inline bool
-issignalingnan(float f)
-{
-    return std::isnan(f) && (bits(f)&0x00400000) == 0;
-}
-
-inline float
-load(float mem)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    asm volatile("flw %0,%1"
-        : "=f" (fd)
-        : "m" (mem));
-    return fd;
-}
-
-inline float
-store(float fs)
-{
-    float mem = std::numeric_limits<float>::signaling_NaN();
-    asm volatile("fsw %1,%0" : "=m" (mem) : "f" (fs));
-    return mem;
-}
-
-inline uint64_t
-frflags()
-{
-    uint64_t rd = -1;
-    asm volatile("frflags %0" : "=r" (rd));
-    return rd;
-}
-
-inline uint64_t
-fsflags(uint64_t rs1)
-{
-    uint64_t rd = -1;
-    asm volatile("fsflags %0,%1" : "=r" (rd) : "r" (rs1));
-    return rd;
-}
-
-inline float
-fmadd_s(float fs1, float fs2, float fs3)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FR4OP("fmadd.s", fd, fs1, fs2, fs3);
-    return fd;
-}
-
-inline float
-fmsub_s(float fs1, float fs2, float fs3)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FR4OP("fmsub.s", fd, fs1, fs2, fs3);
-    return fd;
-}
-
-inline float
-fnmsub_s(float fs1, float fs2, float fs3)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FR4OP("fnmsub.s", fd, fs1, fs2, fs3);
-    return fd;
-}
-
-inline float
-fnmadd_s(float fs1, float fs2, float fs3)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FR4OP("fnmadd.s", fd, fs1, fs2, fs3);
-    return fd;
-}
-
-inline float
-fadd_s(float fs1, float fs2)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FROP("fadd.s", fd, fs1, fs2);
-    return fd;
-}
-
-inline float
-fsub_s(float fs1, float fs2)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FROP("fsub.s", fd, fs1, fs2);
-    return fd;
-}
-
-inline float
-fmul_s(float fs1, float fs2)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FROP("fmul.s", fd, fs1, fs2);
-    return fd;
-}
-
-inline float
-fdiv_s(float fs1, float fs2)
-{
-
-    float fd = 0.0;
-    FROP("fdiv.s", fd, fs1, fs2);
-    return fd;
-}
-
-inline float
-fsqrt_s(float fs1)
-{
-    float fd = std::numeric_limits<float>::infinity();
-    asm volatile("fsqrt.s %0,%1" : "=f" (fd) : "f" (fs1));
-    return fd;
-}
-
-inline float
-fsgnj_s(float fs1, float fs2)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FROP("fsgnj.s", fd, fs1, fs2);
-    return fd;
-}
-
-inline float
-fsgnjn_s(float fs1, float fs2)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FROP("fsgnjn.s", fd, fs1, fs2);
-    return fd;
-}
-
-inline float
-fsgnjx_s(float fs1, float fs2)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FROP("fsgnjx.s", fd, fs1, fs2);
-    return fd;
-}
-
-inline float
-fmin_s(float fs1, float fs2)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FROP("fmin.s", fd, fs1, fs2);
-    return fd;
-}
-
-inline float
-fmax_s(float fs1, float fs2)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    FROP("fmax.s", fd, fs1, fs2);
-    return fd;
-}
-
-inline int64_t
-fcvt_w_s(float fs1)
-{
-    int64_t rd = 0;
-    asm volatile("fcvt.w.s %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline uint64_t
-fcvt_wu_s(float fs1)
-{
-    uint64_t rd = 0;
-    asm volatile("fcvt.wu.s %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline uint64_t
-fmv_x_s(float fs1)
-{
-    uint64_t rd = 0;
-    asm volatile("fmv.x.s %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline bool
-feq_s(float fs1, float fs2)
-{
-    bool rd = false;
-    asm volatile("feq.s %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2));
-    return rd;
-}
-
-inline bool
-flt_s(float fs1, float fs2)
-{
-    bool rd = false;
-    asm volatile("flt.s %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2));
-    return rd;
-}
-
-inline bool
-fle_s(float fs1, float fs2)
-{
-    bool rd = false;
-    asm volatile("fle.s %0,%1,%2" : "=r" (rd) : "f" (fs1), "f" (fs2));
-    return rd;
-}
-
-inline uint64_t
-fclass_s(float fs1)
-{
-    uint64_t rd = -1;
-    asm volatile("fclass.s %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline float
-fcvt_s_w(int64_t rs1)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    asm volatile("fcvt.s.w %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-inline float
-fcvt_s_wu(uint64_t rs1)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    asm volatile("fcvt.s.wu %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-inline float
-fmv_s_x(uint64_t rs1)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    asm volatile("fmv.s.x %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-inline uint64_t
-frcsr()
-{
-    uint64_t rd = -1;
-    asm volatile("frcsr %0" : "=r" (rd));
-    return rd;
-}
-
-inline uint64_t
-frrm()
-{
-    uint64_t rd = -1;
-    asm volatile("frrm %0" : "=r" (rd));
-    return rd;
-}
-
-inline uint64_t
-fscsr(uint64_t rs1)
-{
-    uint64_t rd = -1;
-    asm volatile("fscsr %0,%1" : "=r" (rd) : "r" (rs1));
-    return rd;
-}
-
-inline uint64_t
-fsrm(uint64_t rs1)
-{
-    uint64_t rd = -1;
-    asm volatile("fsrm %0,%1" : "=r" (rd) : "r" (rs1));
-    return rd;
-}
-
-inline int64_t
-fcvt_l_s(float fs1)
-{
-    int64_t rd = 0;
-    asm volatile("fcvt.l.s %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline uint64_t
-fcvt_lu_s(float fs1)
-{
-
-    int64_t rd = 0;
-    asm volatile("fcvt.lu.s %0,%1" : "=r" (rd) : "f" (fs1));
-    return rd;
-}
-
-inline float
-fcvt_s_l(int64_t rs1)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    asm volatile("fcvt.s.l %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-inline float
-fcvt_s_lu(uint64_t rs1)
-{
-    float fd = std::numeric_limits<float>::signaling_NaN();
-    asm volatile("fcvt.s.lu %0,%1" : "=f" (fd) : "r" (rs1));
-    return fd;
-}
-
-} // namespace F
diff --git a/src/insttest/rv64i.cpp b/src/insttest/rv64i.cpp
deleted file mode 100644
index 22a5259..0000000
--- a/src/insttest/rv64i.cpp
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cstdint>
-#include <cstring>
-#include <iostream>
-#include <limits>
-
-#include "insttest.h"
-#include "rv64i.h"
-
-int main()
-{
-    using namespace std;
-    using namespace insttest;
-
-    // LUI
-    expect<int64_t>(4096, []{return I::lui(1);}, "lui");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return I::lui(0x80000);}, "lui, negative");
-
-    // AUIPC
-    expect<bool>(true, []{return I::auipc(3);}, "auipc");
-
-    // Jump (JAL, JALR)
-    expect<bool>(true, []{return I::jal();}, "jal");
-    expect<bool>(true, []{return I::jalr();}, "jalr");
-
-    // BEQ
-    expect<bool>(true, []{return I::beq(5, 5);}, "beq, equal");
-    expect<bool>(false, []{return I::beq(numeric_limits<int64_t>::max(),
-            numeric_limits<int64_t>::min());}, "beq, not equal");
-
-    // BNE
-    expect<bool>(false, []{return I::bne(5, 5);}, "bne, equal");
-    expect<bool>(true, []{return I::bne(numeric_limits<int64_t>::max(),
-            numeric_limits<int64_t>::min());}, "bne, not equal");
-
-    // BLT
-    expect<bool>(true, []{return I::blt(numeric_limits<int64_t>::min(),
-            numeric_limits<int64_t>::max());}, "blt, less");
-    expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::min(),
-            numeric_limits<int64_t>::min());}, "blt, equal");
-    expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::max(),
-            numeric_limits<int64_t>::min());}, "blt, greater");
-
-    // BGE
-    expect<bool>(false, []{return I::bge(numeric_limits<int64_t>::min(),
-            numeric_limits<int64_t>::max());}, "bge, less");
-    expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::min(),
-            numeric_limits<int64_t>::min());}, "bge, equal");
-    expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::max(),
-            numeric_limits<int64_t>::min());}, "bge, greater");
-
-    // BLTU
-    expect<bool>(true, []{return I::blt(numeric_limits<int64_t>::min(),
-            numeric_limits<int64_t>::max());}, "bltu, greater");
-    expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::min(),
-            numeric_limits<int64_t>::min());}, "bltu, equal");
-    expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::max(),
-            numeric_limits<int64_t>::min());}, "bltu, less");
-
-    // BGEU
-    expect<bool>(false, []{return I::bge(numeric_limits<int64_t>::min(),
-            numeric_limits<int64_t>::max());}, "bgeu, greater");
-    expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::min(),
-            numeric_limits<int64_t>::min());}, "bgeu, equal");
-    expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::max(),
-            numeric_limits<int64_t>::min());}, "bgeu, less");
-
-    // Load (LB, LH, LW, LBU, LHU)
-    expect<int64_t>(7, []{return I::load<int8_t, int64_t>(0x07);},
-            "lb, positive");
-    expect<int64_t>(numeric_limits<int8_t>::min(),
-            []{return I::load<int8_t, int64_t>(0x80);}, "lb, negative");
-    expect<int64_t>(1792, []{return I::load<int16_t, int64_t>(0x0700);},
-            "lh, positive");
-    expect<int64_t>(numeric_limits<int16_t>::min(),
-            []{return I::load<int16_t, int64_t>(0x8000);}, "lh, negative");
-    expect<int64_t>(458752, []{return I::load<int32_t, int64_t>(0x00070000);},
-            "lw, positive");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return I::load<int32_t, int64_t>(0x80000000);},
-            "lw, negative");
-    expect<uint64_t>(128, []{return I::load<uint8_t, uint64_t>(0x80);}, "lbu");
-    expect<uint64_t>(32768, []{return I::load<uint16_t, uint64_t>(0x8000);},
-            "lhu");
-
-    // Store (SB, SH, SW)
-    expect<uint8_t>(0xFF, []{return I::store<int8_t>(-1);}, "sb");
-    expect<uint16_t>(0xFFFF, []{return I::store<int16_t>(-1);}, "sh");
-    expect<uint32_t>(0xFFFFFFFF, []{return I::store<int32_t>(-1);}, "sw");
-
-    // ADDI
-    expect<int64_t>(1073742078, []{return I::addi(0x3FFFFFFF, 255);},
-            "addi");
-    expect<int64_t>(1, []{return I::addi(-1, 2);}, "addi, overflow");
-
-    // SLTI
-    expect<bool>(true, []{return I::slti(-1, 0);}, "slti, true");
-    expect<bool>(false, []{return I::slti(0, -1);}, "slti, false");
-
-    // SLTIU
-    expect<bool>(false, []{return I::sltiu(-1, 0);}, "sltiu, false");
-    expect<bool>(true, []{return I::sltiu(0, -1);}, "sltiu, true");
-    expect<bool>(true, []{return I::sltiu(0xFFFF, -1);}, "sltiu, sext");
-
-    // XORI
-    expect<uint64_t>(0xFF, []{return I::xori(0xAA, 0x55);}, "xori (1)");
-    expect<uint64_t>(0, []{return I::xori(0xAA, 0xAA);}, "xori (0)");
-
-    // ORI
-    expect<uint64_t>(0xFF, []{return I::ori(0xAA, 0x55);}, "ori (1)");
-    expect<uint64_t>(0xAA, []{return I::ori(0xAA, 0xAA);}, "ori (A)");
-
-    // ANDI
-    expect<uint64_t>(0, []{return I::andi(-1, 0);}, "andi (0)");
-    expect<uint64_t>(0x1234567812345678ULL,
-            []{return I::andi(0x1234567812345678ULL, -1);}, "andi (1)");
-
-    // SLLI
-    expect<int64_t>(65280, []{return I::slli(255, 8);}, "slli, general");
-    expect<int64_t>(numeric_limits<int64_t>::min(),
-            []{return I::slli(255, 63);}, "slli, erase");
-
-    // SRLI
-    expect<int64_t>(255, []{return I::srli(65280, 8);}, "srli, general");
-    expect<int64_t>(0, []{return I::srli(255, 8);}, "srli, erase");
-    expect<int64_t>(1, []{return I::srli(numeric_limits<int64_t>::min(), 63);},
-            "srli, negative");
-
-    // SRAI
-    expect<int64_t>(255, []{return I::srai(65280, 8);}, "srai, general");
-    expect<int64_t>(0, []{return I::srai(255, 8);}, "srai, erase");
-    expect<int64_t>(-1,
-            []{return I::srai(numeric_limits<int64_t>::min(), 63);},
-            "srai, negative");
-
-    // ADD
-    expect<int64_t>(1073742078, []{return I::add(0x3FFFFFFF, 255);}, "add");
-    expect<int64_t>(-1,
-            []{return I::add(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);},
-            "add, overflow");
-
-    // SUB
-    expect<int64_t>(65535, []{return I::sub(65536, 1);}, "sub");
-    expect<int64_t>(-1,
-            []{return I::sub(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);},
-            "sub, \"overflow\"");
-
-    // SLL
-    expect<int64_t>(65280, []{return I::sll(255, 8);}, "sll, general");
-    expect<int64_t>(numeric_limits<int64_t>::min(),
-            []{return I::sll(255, 63);}, "sll, erase");
-
-    // SLT
-    expect<bool>(true, []{return I::slt(-1, 0);}, "slt, true");
-    expect<bool>(false, []{return I::slt(0, -1);}, "slt, false");
-
-    // SLTU
-    expect<bool>(false, []{return I::sltu(-1, 0);}, "sltu, false");
-    expect<bool>(true, []{return I::sltu(0, -1);}, "sltu, true");
-
-    // XOR
-    expect<uint64_t>(-1,
-            []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL,
-                    0x5555555555555555ULL);},
-            "xor (1)");
-    expect<uint64_t>(0,
-            []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL,
-                    0xAAAAAAAAAAAAAAAAULL);},
-            "xor (0)");
-
-    // SRL
-    expect<uint64_t>(255, []{return I::srl(65280, 8);}, "srl, general");
-    expect<uint64_t>(0, []{return I::srl(255, 8);}, "srl, erase");
-    expect<uint64_t>(1, []{return I::srl(numeric_limits<int64_t>::min(), 63);},
-            "srl, negative");
-
-    // SRA
-    expect<int64_t>(255, []{return I::sra(65280, 8);}, "sra, general");
-    expect<int64_t>(0, []{return I::sra(255, 8);}, "sra, erase");
-    expect<int64_t>(-1, []{return I::sra(numeric_limits<int64_t>::min(), 63);},
-            "sra, negative");
-
-    // OR
-    expect<uint64_t>(-1,
-            []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL,
-                    0x5555555555555555ULL);},
-            "or (1)");
-    expect<uint64_t>(0xAAAAAAAAAAAAAAAAULL,
-            []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL,
-                    0xAAAAAAAAAAAAAAAAULL);},
-            "or (A)");
-
-    // AND
-    expect<uint64_t>(0, []{return I::and_inst(-1, 0);}, "and (0)");
-    expect<uint64_t>(0x1234567812345678ULL,
-            []{return I::and_inst(0x1234567812345678ULL, -1);}, "and (-1)");
-
-    // FENCE/FENCE.I
-    asm volatile("fence" : : );
-    asm volatile("fence.i" : : );
-
-    // ECALL
-    char fname[] = "test.txt";
-    char teststr[] = "this is a test";
-    expect<bool>(true, [=]{
-            int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644);
-            if (fd < 0) {
-                return false;
-            }
-            size_t n = write(fd, teststr, sizeof(teststr));
-            cout << "Bytes written: " << n << endl;
-            return close(fd) >= 0 && n > 0;
-        }, "open, write");
-    expect<int>(0, [=]{return access(fname, F_OK);}, "access F_OK");
-    expect<int>(0, [=]{return access(fname, R_OK);}, "access R_OK");
-    expect<int>(0, [=]{return access(fname, W_OK);}, "access W_OK");
-    // gem5's implementation of access is incorrect; it should return
-    // -1 on failure, not -errno.  Account for this using an inequality.
-    expect<bool>(true, [=]{return access(fname, X_OK) != 0;}, "access X_OK");
-    expect<bool>(true, [=]{
-            struct stat stat_buf, fstat_buf;
-            int s = stat(fname, &stat_buf);
-            if (s < 0) {
-                return false;
-            } else {
-                cout << "stat:" << endl;
-                cout << "\tst_dev =\t" << stat_buf.st_dev << endl;
-                cout << "\tst_ino =\t" << stat_buf.st_ino << endl;
-                cout << "\tst_mode =\t" << stat_buf.st_mode << endl;
-                cout << "\tst_nlink =\t" << stat_buf.st_nlink << endl;
-                cout << "\tst_uid =\t" << stat_buf.st_uid << endl;
-                cout << "\tst_gid =\t" << stat_buf.st_gid << endl;
-                cout << "\tst_rdev =\t" << stat_buf.st_rdev << endl;
-                cout << "\tst_size =\t" << stat_buf.st_size << endl;
-                cout << "\tst_blksize =\t" << stat_buf.st_blksize << endl;
-                cout << "\tst_blocks =\t" << stat_buf.st_blocks << endl;
-            }
-            int fd = open(fname, O_RDONLY);
-            if (fd < 0) {
-                return false;
-            }
-            int f = fstat(fd, &fstat_buf);
-            if (f >= 0) {
-                cout << "fstat:" << endl;
-                cout << "\tst_dev =\t" << fstat_buf.st_dev << endl;
-                cout << "\tst_ino =\t" << fstat_buf.st_ino << endl;
-                cout << "\tst_mode =\t" << fstat_buf.st_mode << endl;
-                cout << "\tst_nlink =\t" << fstat_buf.st_nlink << endl;
-                cout << "\tst_uid =\t" << fstat_buf.st_uid << endl;
-                cout << "\tst_gid =\t" << fstat_buf.st_gid << endl;
-                cout << "\tst_rdev =\t" << fstat_buf.st_rdev << endl;
-                cout << "\tst_size =\t" << fstat_buf.st_size << endl;
-                cout << "\tst_blksize =\t" << fstat_buf.st_blksize << endl;
-                cout << "\tst_blocks =\t" << fstat_buf.st_blocks << endl;
-            }
-            return close(fd) >= 0 && f >= 0;
-        }, "open, stat");
-    expect<bool>(true, [=]{
-            int fd = open(fname, O_RDONLY);
-            if (fd < 0) {
-                return false;
-            }
-            char in[128];
-            size_t n = read(fd, in, sizeof(in));
-            cout << "Bytes read: " << n << endl;
-            cout << "String read: " << in << endl;
-            int cl = close(fd);
-            int un = unlink(fname);
-            return n > 0 && cl >= 0 && un >= 0 && strcmp(teststr, in) == 0;
-        }, "open, read, unlink");
-    expect<bool>(true, []{
-            struct tms buf;
-            clock_t t = times(&buf);
-            cout << "times:" << endl;
-            cout << "\ttms_utime =\t" << buf.tms_utime << endl;
-            cout << "\ttms_stime =\t" << buf.tms_stime << endl;
-            cout << "\ttms_cutime =\t" << buf.tms_cutime << endl;
-            cout << "\ttms_cstime =\t" << buf.tms_cstime << endl;
-            return t > 0;
-        }, "times");
-    expect<int>(0, []{
-            struct timeval time;
-            int res = gettimeofday(&time, nullptr);
-            cout << "timeval:" << endl;
-            cout << "\ttv_sec =\t" << time.tv_sec << endl;
-            cout << "\ttv_usec =\t" << time.tv_usec << endl;
-            return res;
-        }, "gettimeofday");
-
-    // EBREAK not tested because it only makes sense in FS mode or when
-    // using gdb
-
-    // ERET not tested because it only makes sense in FS mode and will cause
-    // a panic when used in SE mode
-
-    // CSRs (RDCYCLE, RDTIME, RDINSTRET)
-    expect<bool>(true, []{
-                uint64_t cycles = 0;
-                asm("rdcycle %0" : "=r" (cycles));
-                cout << "Cycles: " << cycles << endl;
-                return cycles > 0;
-            }, "rdcycle");
-    expect<bool>(true, []{
-                uint64_t time = 0;
-                asm("rdtime %0" : "=r" (time));
-                return time > 0;
-            }, "rdtime");
-    expect<bool>(true, []{
-                uint64_t instret = 0;
-                asm("rdinstret %0" : "=r" (instret));
-                cout << "Instructions Retired: " << instret << endl;
-                return instret > 0;
-            }, "rdinstret");
-
-    // 64-bit memory (LWU, LD, SD)
-    expect<int64_t>(0xFFFFFFFF, []{return I::load<uint32_t, uint64_t>(-1);},
-            "lwu");
-    expect<int64_t>(30064771072,
-            []{return I::load<int64_t, int64_t>(30064771072);}, "ld");
-    expect<uint64_t>(-1, []{return I::store<int64_t>(-1);}, "sd");
-
-    // ADDIW
-    expect<int64_t>(268435710, []{return I::addiw(0x0FFFFFFF, 255);}, "addiw");
-    expect<int64_t>(-2147481602, []{return I::addiw(0x7FFFFFFF, 0x7FF);},
-            "addiw, overflow");
-    expect<int64_t>(0, []{return I::addiw(0x7FFFFFFFFFFFFFFFLL, 1);},
-            "addiw, truncate");
-
-    // SLLIW
-    expect<int64_t>(65280, []{return I::slliw(255, 8);}, "slliw, general");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return I::slliw(255, 31);}, "slliw, erase");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return I::slliw(0xFFFFFFFF00800000LL, 8);}, "slliw, truncate");
-
-    // SRLIW
-    expect<int64_t>(255, []{return I::srliw(65280, 8);}, "srliw, general");
-    expect<int64_t>(0, []{return I::srliw(255, 8);}, "srliw, erase");
-    expect<int64_t>(1,
-            []{return I::srliw(numeric_limits<int32_t>::min(), 31);},
-            "srliw, negative");
-    expect<int64_t>(1, []{return I::srliw(0xFFFFFFFF80000000LL, 31);},
-            "srliw, truncate");
-
-    // SRAIW
-    expect<int64_t>(255, []{return I::sraiw(65280, 8);}, "sraiw, general");
-    expect<int64_t>(0, []{return I::sraiw(255, 8);}, "sraiw, erase");
-    expect<int64_t>(-1,
-            []{return I::sraiw(numeric_limits<int32_t>::min(), 31);},
-            "sraiw, negative");
-    expect<int64_t>(-1, []{return I::sraiw(0x0000000180000000LL, 31);},
-            "sraiw, truncate");
-
-    // ADDW
-    expect<int64_t>(1073742078, []{return I::addw(0x3FFFFFFF, 255);}, "addw");
-    expect<int64_t>(-1, []{return I::addw(0x7FFFFFFF, 0x80000000);},
-            "addw, overflow");
-    expect<int64_t>(65536, []{return I::addw(0xFFFFFFFF0000FFFFLL, 1);},
-            "addw, truncate");
-
-    // SUBW
-    expect<int64_t>(65535, []{return I::subw(65536, 1);}, "subw");
-    expect<int64_t>(-1, []{return I::subw(0x7FFFFFFF, 0x80000000);},
-            "subw, \"overflow\"");
-    expect<int64_t>(0,
-            []{return I::subw(0xAAAAAAAAFFFFFFFFULL, 0x55555555FFFFFFFFULL);},
-            "subw, truncate");
-
-    // SLLW
-    expect<int64_t>(65280, []{return I::sllw(255, 8);}, "sllw, general");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return I::sllw(255, 31);}, "sllw, erase");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return I::sllw(0xFFFFFFFF00008000LL, 16);}, "sllw, truncate");
-
-    // SRLW
-    expect<uint64_t>(255, []{return I::srlw(65280, 8);}, "srlw, general");
-    expect<uint64_t>(0, []{return I::srlw(255, 8);}, "srlw, erase");
-    expect<uint64_t>(1,
-            []{return I::srlw(numeric_limits<int32_t>::min(), 31);},
-            "srlw, negative");
-    expect<uint64_t>(1, []{return I::srlw(0x0000000180000000LL, 31);},
-            "srlw, truncate");
-
-    // SRAW
-    expect<int64_t>(255, []{return I::sraw(65280, 8);}, "sraw, general");
-    expect<int64_t>(0, []{return I::sraw(255, 8);}, "sraw, erase");
-    expect<int64_t>(-1,
-            []{return I::sraw(numeric_limits<int32_t>::min(), 31);},
-            "sraw, negative");
-    expect<int64_t>(1, []{return I::sraw(0xFFFFFFFF40000000LL, 30);},
-            "sraw, truncate");
-
-    return 0;
-}
diff --git a/src/insttest/rv64i.h b/src/insttest/rv64i.h
deleted file mode 100644
index 198fb36..0000000
--- a/src/insttest/rv64i.h
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#pragma once
-
-#include <cstdint>
-#include <iostream>
-
-#include "insttest.h"
-
-namespace I
-{
-
-inline uint64_t
-lui(const uint32_t imm)
-{
-    int64_t rd = -1;
-    asm volatile("lui %0,%1" : "=r" (rd) : "i" (imm));
-    return rd;
-}
-
-inline bool
-auipc(const uint64_t imm)
-{
-    int64_t rd = -1;
-    asm volatile("auipc %0,%1" : "=r" (rd) : "i" (imm));
-    std::cout << "auipc: 0x" << std::hex << std::uppercase << rd <<
-        std::nouppercase << std::dec << std::endl;
-    return rd >= imm;
-}
-
-inline bool
-jal()
-{
-    asm volatile goto("jal zero,%l[jallabel]" : : : : jallabel);
-    return false;
-  jallabel:
-    return true;
-}
-
-inline bool
-jalr()
-{
-    int a = 0;
-    asm volatile("auipc %0,0;"
-                 "jalr t0,%0,12;"
-                 "addi %0,zero,0;"
-                 "sub %0,t0,%0;"
-                 : "+r" (a)
-                 :
-                 : "t0");
-    return a == 8;
-}
-
-inline bool
-beq(int64_t a, int64_t b)
-{
-    asm volatile goto("beq %0,%1,%l[beqlabel]"
-            :
-            : "r" (a), "r" (b)
-            :
-            : beqlabel);
-    return false;
-  beqlabel:
-    return true;
-}
-
-inline bool
-bne(int64_t a, int64_t b)
-{
-    asm volatile goto("bne %0,%1,%l[bnelabel]"
-            :
-            : "r" (a), "r" (b)
-            :
-            : bnelabel);
-    return false;
-  bnelabel:
-    return true;
-}
-
-inline bool
-blt(int64_t a, int64_t b)
-{
-    asm volatile goto("blt %0,%1,%l[bltlabel]"
-            :
-            : "r" (a), "r" (b)
-            :
-            : bltlabel);
-    return false;
-  bltlabel:
-    return true;
-}
-
-inline bool
-bge(int64_t a, int64_t b)
-{
-    asm volatile goto("bge %0,%1,%l[bgelabel]"
-            :
-            : "r" (a), "r" (b)
-            :
-            : bgelabel);
-    return false;
-  bgelabel:
-    return true;
-}
-
-inline bool
-bltu(uint64_t a, uint64_t b)
-{
-    asm volatile goto("bltu %0,%1,%l[bltulabel]"
-            :
-            : "r" (a), "r" (b)
-            :
-            : bltulabel);
-    return false;
-  bltulabel:
-    return true;
-}
-
-inline bool
-bgeu(uint64_t a, uint64_t b)
-{
-    asm volatile goto("bgeu %0,%1,%l[bgeulabel]"
-            :
-            : "r" (a), "r" (b)
-            :
-            : bgeulabel);
-    return false;
-  bgeulabel:
-    return true;
-}
-
-template<typename M, typename R> inline R
-load(const M& b)
-{
-    R a = 0;
-    switch(sizeof(M))
-    {
-      case 1:
-        if (std::is_signed<M>::value) {
-            asm volatile("lb %0,%1" : "=r" (a) : "m" (b));
-        } else {
-            asm volatile("lbu %0,%1" : "=r" (a) : "m" (b));
-        }
-        break;
-      case 2:
-        if (std::is_signed<M>::value) {
-            asm volatile("lh %0,%1" : "=r" (a) : "m" (b));
-        } else {
-            asm volatile("lhu %0,%1" : "=r" (a) : "m" (b));
-        }
-        break;
-      case 4:
-        if (std::is_signed<M>::value) {
-            asm volatile("lw %0,%1" : "=r" (a) : "m" (b));
-        } else {
-            asm volatile("lwu %0,%1" : "=r" (a) : "m" (b));
-        }
-        break;
-      case 8:
-        asm volatile("ld %0,%1" : "=r" (a) : "m" (b));
-        break;
-    }
-    return a;
-}
-
-template<typename M> inline M
-store(const M& rs2)
-{
-    M mem = 0;
-    switch (sizeof(M))
-    {
-      case 1:
-        asm volatile("sb %1,%0" : "=m" (mem) : "r" (rs2));
-        break;
-      case 2:
-        asm volatile("sh %1,%0" : "=m" (mem) : "r" (rs2));
-        break;
-      case 4:
-        asm volatile("sw %1,%0" : "=m" (mem) : "r" (rs2));
-        break;
-      case 8:
-        asm volatile("sd %1,%0" : "=m" (mem) : "r" (rs2));
-        break;
-    }
-    return mem;
-}
-
-inline int64_t
-addi(int64_t rs1, const int16_t imm)
-{
-    int64_t rd = 0;
-    IOP("addi", rd, rs1, imm);
-    return rd;
-}
-
-inline bool
-slti(int64_t rs1, const int16_t imm)
-{
-    bool rd = false;
-    IOP("slti", rd, rs1, imm);
-    return rd;
-}
-
-inline bool
-sltiu(uint64_t rs1, const uint16_t imm)
-{
-    bool rd = false;
-    IOP("sltiu", rd, rs1, imm);
-    return rd;
-}
-
-inline uint64_t
-xori(uint64_t rs1, const uint16_t imm)
-{
-    uint64_t rd = 0;
-    IOP("xori", rd, rs1, imm);
-    return rd;
-}
-
-inline uint64_t
-ori(uint64_t rs1, const uint16_t imm)
-{
-    uint64_t rd = 0;
-    IOP("ori", rd, rs1, imm);
-    return rd;
-}
-
-inline uint64_t
-andi(uint64_t rs1, const uint16_t imm)
-{
-    uint64_t rd = 0;
-    IOP("andi", rd, rs1, imm);
-    return rd;
-}
-
-inline int64_t
-slli(int64_t rs1, const uint16_t imm)
-{
-    int64_t rd = 0;
-    IOP("slli", rd, rs1, imm);
-    return rd;
-}
-
-inline uint64_t
-srli(uint64_t rs1, const uint16_t imm)
-{
-    uint64_t rd = 0;
-    IOP("srli", rd, rs1, imm);
-    return rd;
-}
-
-inline int64_t
-srai(int64_t rs1, const uint16_t imm)
-{
-    int64_t rd = 0;
-    IOP("srai", rd, rs1, imm);
-    return rd;
-}
-
-inline int64_t
-add(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("add", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-sub(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("sub", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-sll(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("sll", rd, rs1, rs2);
-    return rd;
-}
-
-inline bool
-slt(int64_t rs1, int64_t rs2)
-{
-    bool rd = false;
-    ROP("slt", rd, rs1, rs2);
-    return rd;
-}
-
-inline bool
-sltu(uint64_t rs1, uint64_t rs2)
-{
-    bool rd = false;
-    ROP("sltu", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-xor_inst(uint64_t rs1, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("xor", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-srl(uint64_t rs1, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("srl", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-sra(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("sra", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-or_inst(uint64_t rs1, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("or", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-and_inst(uint64_t rs1, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("and", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-addiw(int64_t rs1, const int16_t imm)
-{
-    int64_t rd = 0;
-    IOP("addiw", rd, rs1, imm);
-    return rd;
-}
-
-inline int64_t
-slliw(int64_t rs1, const uint16_t imm)
-{
-    int64_t rd = 0;
-    IOP("slliw", rd, rs1, imm);
-    return rd;
-}
-
-inline uint64_t
-srliw(uint64_t rs1, const uint16_t imm)
-{
-    uint64_t rd = 0;
-    IOP("srliw", rd, rs1, imm);
-    return rd;
-}
-
-inline int64_t
-sraiw(int64_t rs1, const uint16_t imm)
-{
-    int64_t rd = 0;
-    IOP("sraiw", rd, rs1, imm);
-    return rd;
-}
-
-inline int64_t
-addw(int64_t rs1,  int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("addw", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-subw(int64_t rs1,  int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("subw", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-sllw(int64_t rs1,  int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("sllw", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-srlw(uint64_t rs1,  uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("srlw", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-sraw(int64_t rs1,  int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("sraw", rd, rs1, rs2);
-    return rd;
-}
-
-} // namespace I
diff --git a/src/insttest/rv64m.cpp b/src/insttest/rv64m.cpp
deleted file mode 100644
index 836d771..0000000
--- a/src/insttest/rv64m.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#include <cstdint>
-#include <limits>
-
-#include "insttest.h"
-#include "rv64m.h"
-
-int main()
-{
-    using namespace std;
-    using namespace insttest;
-
-    // MUL
-    expect<int64_t>(39285, []{return M::mul(873, 45);}, "mul");
-    expect<int64_t>(0, []{return M::mul(0x4000000000000000LL, 4);},
-            "mul, overflow");
-
-    // MULH
-    expect<int64_t>(1, []{return M::mulh(0x4000000000000000LL, 4);}, "mulh");
-    expect<int64_t>(-1, []{return M::mulh(numeric_limits<int64_t>::min(), 2);},
-            "mulh, negative");
-    expect<int64_t>(0, []{return M::mulh(-1, -1);}, "mulh, all bits set");
-
-    // MULHSU
-    expect<int64_t>(-1, []{return M::mulhsu(-1, -1);}, "mulhsu, all bits set");
-    expect<int64_t>(-1,
-            []{return M::mulhsu(numeric_limits<int64_t>::min(), 2);},\
-            "mulhsu");
-
-    // MULHU
-    expect<uint64_t>(1, []{return M::mulhu(0x8000000000000000ULL, 2);},
-            "mulhu");
-    expect<uint64_t>(0xFFFFFFFFFFFFFFFEULL, []{return M::mulhu(-1, -1);},
-            "mulhu, all bits set");
-
-    // DIV
-    expect<int64_t>(-7, []{return M::div(-59, 8);}, "div");
-    expect<int64_t>(-1, []{return M::div(255, 0);}, "div/0");
-    expect<int64_t>(numeric_limits<int64_t>::min(),
-            []{return M::div(numeric_limits<int64_t>::min(), -1);},
-            "div, overflow");
-
-    // DIVU
-    expect<uint64_t>(2305843009213693944LL, []{return M::divu(-59, 8);},
-            "divu");
-    expect<uint64_t>(numeric_limits<uint64_t>::max(),
-            []{return M::divu(255, 0);}, "divu/0");
-    expect<uint64_t>(0,
-            []{return M::divu(numeric_limits<uint64_t>::min(), -1);},
-            "divu, \"overflow\"");
-
-    // REM
-    expect<int64_t>(-3, []{return M::rem(-59, 8);}, "rem");
-    expect<int64_t>(255, []{return M::rem(255, 0);}, "rem/0");
-    expect<int64_t>(0, []{return M::rem(numeric_limits<int64_t>::min(), -1);},
-            "rem, overflow");
-
-    // REMU
-    expect<uint64_t>(5, []{return M::remu(-59, 8);}, "remu");
-    expect<uint64_t>(255, []{return M::remu(255, 0);}, "remu/0");
-    expect<uint64_t>(0x8000000000000000ULL,
-            []{return M::remu(0x8000000000000000ULL, -1);},
-            "remu, \"overflow\"");
-
-    // MULW
-    expect<int64_t>(-100,
-            []{return M::mulw(0x7FFFFFFF00000005LL, 0x80000000FFFFFFECLL);},
-            "mulw, truncate");
-    expect<int64_t>(0, []{return M::mulw(0x40000000, 4);}, "mulw, overflow");
-
-    // DIVW
-    expect<int64_t>(-7,
-            []{return M::divw(0x7FFFFFFFFFFFFFC5LL, 0xFFFFFFFF00000008LL);},
-            "divw, truncate");
-    expect<int64_t>(-1, []{return M::divw(65535, 0);}, "divw/0");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return M::divw(numeric_limits<int32_t>::min(), -1);},
-            "divw, overflow");
-
-    // DIVUW
-    expect<int64_t>(536870904,
-            []{return M::divuw(0x7FFFFFFFFFFFFFC5LL, 0xFFFFFFFF00000008LL);},
-            "divuw, truncate");
-    expect<int64_t>(numeric_limits<uint64_t>::max(),
-            []{return M::divuw(65535, 0);}, "divuw/0");
-    expect<int64_t>(0,
-            []{return M::divuw(numeric_limits<int32_t>::min(), -1);},
-            "divuw, \"overflow\"");
-    expect<int64_t>(-1,
-            []{return M::divuw(numeric_limits<uint32_t>::max(), 1);},
-            "divuw, sign extend");
-
-    // REMW
-    expect<int64_t>(-3,
-            []{return M::remw(0x7FFFFFFFFFFFFFC5LL, 0xFFFFFFFF00000008LL);},
-            "remw, truncate");
-    expect<int64_t>(65535, []{return M::remw(65535, 0);}, "remw/0");
-    expect<int64_t>(0, []{return M::remw(numeric_limits<int32_t>::min(), -1);},
-            "remw, overflow");
-
-    // REMUW
-    expect<int64_t>(5,
-            []{return M::remuw(0x7FFFFFFFFFFFFFC5LL, 0xFFFFFFFF00000008LL);},
-            "remuw, truncate");
-    expect<int64_t>(65535, []{return M::remuw(65535, 0);}, "remuw/0");
-    expect<int64_t>(numeric_limits<int32_t>::min(),
-            []{return M::remuw(numeric_limits<int32_t>::min(), -1);},
-            "remuw, \"overflow\"");
-    expect<int64_t>(0xFFFFFFFF80000000,
-            []{return M::remuw(0x80000000, 0xFFFFFFFF);},
-            "remuw, sign extend");
-
-    return 0;
-}
diff --git a/src/insttest/rv64m.h b/src/insttest/rv64m.h
deleted file mode 100644
index b93a7d6..0000000
--- a/src/insttest/rv64m.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 2016 The University of Virginia
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Alec Roelke
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "insttest.h"
-
-namespace M
-{
-
-inline int64_t
-mul(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("mul", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-mulh(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("mulh", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-mulhsu(int64_t rs1, uint64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("mulhsu", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-mulhu(uint64_t rs1, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("mulhu", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-div(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("div", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-divu(uint64_t rs1, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("divu", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-rem(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("rem", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-remu(uint64_t rs1, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("remu", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-mulw(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("mulw", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-divw(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("divw", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-divuw(uint64_t rs1, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("divuw", rd, rs1, rs2);
-    return rd;
-}
-
-inline int64_t
-remw(int64_t rs1, int64_t rs2)
-{
-    int64_t rd = 0;
-    ROP("remw", rd, rs1, rs2);
-    return rd;
-}
-
-inline uint64_t
-remuw(uint64_t rs1, uint64_t rs2)
-{
-    uint64_t rd = 0;
-    ROP("remuw", rd, rs1, rs2);
-    return rd;
-}
-
-} // namespace M
diff --git a/src/pthreads/.gitignore b/src/pthreads/.gitignore
deleted file mode 100644
index fc8c9b0..0000000
--- a/src/pthreads/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/bin.*
diff --git a/src/pthreads/Makefile.aarch32 b/src/pthreads/Makefile.aarch32
deleted file mode 100644
index 1acb097..0000000
--- a/src/pthreads/Makefile.aarch32
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) 2019 ARM Limited
-# All rights reserved.
-#
-# The license below extends only to copyright in the software and shall
-# not be construed as granting a license to any other intellectual
-# property including but not limited to intellectual property relating
-# to a hardware implementation of the functionality of the software
-# licensed hereunder.  You may use the software subject to the license
-# terms below provided that you ensure that this notice is replicated
-# unmodified and in its entirety in all distributions of the software,
-# modified or unmodified, in source code or in binary form.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-CROSS_COMPILE = arm-linux-gnueabihf-
-BIN_DIR = bin.aarch32
-
--include Makefile.common
diff --git a/src/pthreads/Makefile.aarch64 b/src/pthreads/Makefile.aarch64
deleted file mode 100644
index da30820..0000000
--- a/src/pthreads/Makefile.aarch64
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) 2019 ARM Limited
-# All rights reserved.
-#
-# The license below extends only to copyright in the software and shall
-# not be construed as granting a license to any other intellectual
-# property including but not limited to intellectual property relating
-# to a hardware implementation of the functionality of the software
-# licensed hereunder.  You may use the software subject to the license
-# terms below provided that you ensure that this notice is replicated
-# unmodified and in its entirety in all distributions of the software,
-# modified or unmodified, in source code or in binary form.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-CROSS_COMPILE = aarch64-linux-gnu-
-BIN_DIR = bin.aarch64
-
--include Makefile.common
diff --git a/src/pthreads/Makefile.common b/src/pthreads/Makefile.common
deleted file mode 100644
index a7385ce..0000000
--- a/src/pthreads/Makefile.common
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright (c) 2019 ARM Limited
-# All rights reserved.
-#
-# The license below extends only to copyright in the software and shall
-# not be construed as granting a license to any other intellectual
-# property including but not limited to intellectual property relating
-# to a hardware implementation of the functionality of the software
-# licensed hereunder.  You may use the software subject to the license
-# terms below provided that you ensure that this notice is replicated
-# unmodified and in its entirety in all distributions of the software,
-# modified or unmodified, in source code or in binary form.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-CC := $(CROSS_COMPILE)$(CC)
-CXX := $(CROSS_COMPILE)$(CXX)
-LD := $(CXX)
-CCFLAGS ?=
-CXXFLAGS ?= -g -O3 -static -std=c++11
-LDFLAGS ?= -pthread
-
-BIN_DIR ?= ./bin
-
-TESTS = test_pthread_create_seq 	\
-	test_pthread_create_para 	\
-	test_pthread_mutex		\
-	test_atomic			\
-	test_pthread_cond		\
-	test_std_thread			\
-	test_std_mutex			\
-	test_std_condition_variable
-
-all: $(addprefix $(BIN_DIR)/,$(TESTS))
-
-$(BIN_DIR)/%: src/%.cpp
-	@mkdir -p $(BIN_DIR)
-	$(CXX) -o $@ $(CCFLAGS) $(CXXFLAGS) $(LDFLAGS) $^
-
-clean:
-	$(RM) -r $(BIN_DIR)
-
-.PHONY: all clean
-
diff --git a/src/pthreads/Makefile.riscv b/src/pthreads/Makefile.riscv
deleted file mode 100644
index ea486a7..0000000
--- a/src/pthreads/Makefile.riscv
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) 2019 ARM Limited
-# All rights reserved.
-#
-# The license below extends only to copyright in the software and shall
-# not be construed as granting a license to any other intellectual
-# property including but not limited to intellectual property relating
-# to a hardware implementation of the functionality of the software
-# licensed hereunder.  You may use the software subject to the license
-# terms below provided that you ensure that this notice is replicated
-# unmodified and in its entirety in all distributions of the software,
-# modified or unmodified, in source code or in binary form.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-CROSS_COMPILE = riscv64-unknown-linux-gnu-
-BIN_DIR = bin.riscv64
-
--include Makefile.common
diff --git a/src/pthreads/Makefile.x86 b/src/pthreads/Makefile.x86
deleted file mode 100644
index 90013cd..0000000
--- a/src/pthreads/Makefile.x86
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) 2019 ARM Limited
-# All rights reserved.
-#
-# The license below extends only to copyright in the software and shall
-# not be construed as granting a license to any other intellectual
-# property including but not limited to intellectual property relating
-# to a hardware implementation of the functionality of the software
-# licensed hereunder.  You may use the software subject to the license
-# terms below provided that you ensure that this notice is replicated
-# unmodified and in its entirety in all distributions of the software,
-# modified or unmodified, in source code or in binary form.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-CROSS_COMPILE =
-BIN_DIR = bin.x86
-
--include Makefile.common
diff --git a/src/simple/.gitignore b/src/simple/.gitignore
new file mode 100644
index 0000000..e2e7327
--- /dev/null
+++ b/src/simple/.gitignore
@@ -0,0 +1 @@
+/out
diff --git a/src/simple/Makefile b/src/simple/Makefile
new file mode 100644
index 0000000..f3113aa
--- /dev/null
+++ b/src/simple/Makefile
@@ -0,0 +1,179 @@
+# Copyright (c) 2020 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+# Input files for each build type. We whitelist barmetal ones,
+# and blacklist
+BARE_INS = \
+  m5_exit \
+  m5_checkpoint
+USER_INS = $(basename $(foreach BASE_DIR, . $(ISA), $(foreach IN_EXT, \
+  $(IN_EXT_ASM) $(IN_EXT_C) $(IN_EXT_CXX), $(wildcard $(BASE_DIR)/*$(IN_EXT)))))
+
+# Input values.
+BOOTLOADER_SRC = bootloader/$(ISA)$(IN_EXT_ASM)
+BOOTLOADER_OBJ = $(OUT_DIR)/bootloader$(OBJ_EXT)
+CC = $(PREFIX)gcc
+CXX = $(PREFIX)g++
+GEM5_ROOT = $(CURDIR)/../../../gem5
+M5OP_OBJ = $(GEM5_ROOT)/util/m5/build/$(M5_ISA)/out/libm5.a
+# Common to USER and BARE.
+CFLAGS = $(CCFLAGS) -std=c11
+# Common to C and C++.
+CCFLAGS = \
+  -I $(GEM5_ROOT)/include/ \
+  -O3 \
+  -Wall \
+  -Werror \
+  -Wextra \
+  -fno-pie \
+  -ggdb3 \
+  -no-pie \
+  -pedantic \
+  -static \
+  $(CCFLAGS_ISA)
+# -Wl,--whole-archive allows C++ threads to work with -static.
+# https://stackoverflow.com/questions/35116327/when-g-static-link-pthread-cause-segmentation-fault-why
+LDFLAGS_USER = \
+  -lrt \
+  -pthread \
+  -Wl,--whole-archive \
+  -lpthread \
+  -Wl,--no-whole-archive
+CCFLAGS_BARE = $(CFLAGS) \
+  -T link.ld \
+  -Wl,--section-start=.text=0x80000000 \
+  -fno-asynchronous-unwind-tables \
+  -fno-unwind-tables \
+  -nostartfiles \
+  -nostdlib
+CFLAGS_USER = $(CFLAGS)
+CXXFLAGS = $(CCFLAGS) -std=c++11
+CXXFLAGS_BARE = $(CXXFLAGS)
+CXXFLAGS_USER = $(CXXFLAGS)
+IN_EXT_ASM = .S
+IN_EXT_C = .c
+IN_EXT_CXX = .cpp
+OUT_DIR_BASE = out
+OUT_DIR = $(OUT_DIR_BASE)/$(ISA)
+OUT_BARE_DIR = $(OUT_DIR)/bare
+OUT_USER_DIR = $(OUT_DIR)/user
+OBJ_EXT = .o
+OUT_EXT = .out
+
+ifeq ($(ISA),)
+ISA = $(shell uname -m)
+endif
+
+ifeq ($(ISA),x86_64)
+CCFLAGS_ISA = -msse3
+M5_ISA = x86
+PREFIX =
+else
+M5_ISA = $(ISA)
+ifeq ($(ISA),aarch64)
+CCFLAGS_ISA = -Xassembler -march=all
+# Input files just for this ISA.
+ISA_BARE_INS = semihost_exit
+# Exclude baremetal only builds.
+USER_INS := $(filter-out $(ISA)/semihost_exit, $(USER_INS))
+# Commented out for now because otherwise adds an
+# empty entry to the target list.
+#ISA_USER_INS =
+PREFIX = aarch64-linux-gnu-
+else
+ifeq ($(ISA),arm)
+PREFIX = arm-linux-gnueabihf-
+else
+ifeq ($(ISA),riscv)
+PREFIX = riscv64-linux-gnu-
+# riscv does not have an util/m5/m5op_
+M5OP_OBJ =
+USER_INS := $(filter-out ./m5_checkpoint ./m5_exit, $(USER_INS))
+else
+$(error unknown isa $(ISA))
+endif
+endif
+endif
+endif
+
+# Calculated values.
+BARE_OUTS = $(addprefix $(OUT_BARE_DIR)/, $(addsuffix $(OUT_EXT), $(BARE_INS) $(addprefix $(ISA)/,$(ISA_BARE_INS))))
+USER_OUTS = $(addprefix $(OUT_USER_DIR)/, $(addsuffix $(OUT_EXT), $(USER_INS)))
+
+.PHONY: all bare clean mkdir user
+
+user: mkdir-user $(USER_OUTS)
+
+bare: mkdir-bare $(BARE_OUTS)
+
+all: bare user
+
+user-show:
+	@echo $(USER_OUTS)
+
+$(OUT_BARE_DIR)/%$(OUT_EXT): %$(IN_EXT_ASM) $(M5OP_OBJ)
+	$(CC) $(CCFLAGS_BARE) -o '$@' $^
+
+$(OUT_USER_DIR)/%$(OUT_EXT): %$(IN_EXT_ASM) $(M5OP_OBJ)
+	$(CC) $(CFLAGS_USER) -o '$@' $^
+
+$(OUT_BARE_DIR)/%$(OUT_EXT): %$(IN_EXT_C) $(M5OP_OBJ) $(BOOTLOADER_OBJ)
+	$(CC) $(CCFLAGS_BARE) -o '$@' $^
+
+$(OUT_USER_DIR)/%$(OUT_EXT): %$(IN_EXT_C) $(M5OP_OBJ)
+	$(CC) $(CFLAGS_USER) -o '$@' $^ $(LDFLAGS_USER)
+
+$(OUT_BARE_DIR)/%$(OUT_EXT): %$(IN_EXT_CXX) $(M5OP_OBJ) $(BOOTLOADER_OBJ)
+	$(CXX) $(CXXFLAGS_BARE) -o '$@' $^
+
+$(OUT_USER_DIR)/%$(OUT_EXT): %$(IN_EXT_CXX) $(M5OP_OBJ)
+	$(CXX) $(CXXFLAGS_USER) -o '$@' $^ $(LDFLAGS_USER)
+
+$(BOOTLOADER_OBJ): $(BOOTLOADER_SRC)
+	$(CC) $(CFLAGS_USER) -c -o '$@' '$<'
+
+$(M5OP_OBJ):
+	cd $(GEM5_ROOT) && scons -C util/m5 build/$(M5_ISA)/out/m5
+
+clean:
+	rm -rf '$(OUT_DIR_BASE)'
+
+mkdir-bare:
+	mkdir -p '$(OUT_BARE_DIR)/$(ISA)'
+
+mkdir-user:
+	mkdir -p '$(OUT_USER_DIR)/$(ISA)'
+
diff --git a/src/simple/README.md b/src/simple/README.md
new file mode 100644
index 0000000..c6b1ced
--- /dev/null
+++ b/src/simple/README.md
@@ -0,0 +1,3 @@
+Simple single input source userland/baremetal executables in C/C++ etc.
+
+How to build explained in `make help`.
diff --git a/src/simple/aarch64/futex_ldxr_stxr.c b/src/simple/aarch64/futex_ldxr_stxr.c
new file mode 100644
index 0000000..b044494
--- /dev/null
+++ b/src/simple/aarch64/futex_ldxr_stxr.c
@@ -0,0 +1,126 @@
+/* Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Correct outcome:
+ * Exiting @ tick 18446744073709551615 because simulate() limit reached
+ * Incorrect behaviour due to: https://gem5.atlassian.net/browse/GEM5-537
+ * Exits successfully. */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <inttypes.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <stdatomic.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#define LDXR_OPS_SIZE 1024
+static int futex1 = 1;
+static int futex2 = 1;
+/* We do this to ensure that those two varibles are well separated.
+ * If they are too close (same cache line?), then the str to ldxr_done
+ * can make CPU1 lose the lock. */
+static uint64_t ldxr_ops[LDXR_OPS_SIZE];
+static uint64_t *ldxr_done = ldxr_ops;
+static uint64_t *ldxr_var = ldxr_ops + LDXR_OPS_SIZE - 1;
+
+void __attribute__ ((noinline)) busy_loop(
+    unsigned long long max,
+    unsigned long long max2
+) {
+    for (unsigned long long i = 0; i < max2; i++) {
+        for (unsigned long long j = 0; j < max; j++) {
+            __asm__ __volatile__ ("" : "+g" (i), "+g" (j) : :);
+        }
+    }
+}
+
+static int
+futex(int *uaddr, int futex_op, int val,
+        const struct timespec *timeout, int *uaddr2, int val3)
+{
+    register uint64_t x0 __asm__ ("x0") = (uint64_t)uaddr;
+    register uint64_t x1 __asm__ ("x1") = futex_op;
+    register uint64_t x2 __asm__ ("x2") = val;
+    register const struct timespec *x3 __asm__ ("x3") = timeout;
+    register int *x4 __asm__ ("x4") = uaddr2;
+    register uint64_t x5 __asm__ ("x5") = val3;
+    register uint64_t x8 __asm__ ("x8") = SYS_futex; /* syscall number */
+    __asm__ __volatile__ (
+        "svc 0;"
+        : "+r" (x0)
+        : "r" (x1), "r" (x2), "r" (x3), "r" (x4), "r" (x5), "r" (x8)
+        : "memory"
+    );
+    return x0;
+}
+
+void* thread_main(void *arg) {
+    (void)arg;
+    __asm__ __volatile__ (
+        "ldxr x0, [%[ldxr_var]];mov %[ldxr_done], 1"
+        : [ldxr_done] "=r" (*ldxr_done)
+        : [ldxr_var] "r" (ldxr_var)
+        : "x0", "memory"
+    );
+    futex(&futex1, FUTEX_WAIT, futex1, NULL, NULL, 0);
+    futex(&futex2, FUTEX_WAIT, futex2, NULL, NULL, 0);
+    return NULL;
+}
+
+int main(void) {
+    pthread_t thread;
+    pthread_create(&thread, NULL, thread_main, NULL);
+    while (!*ldxr_done) {}
+    /* Wait for thread1 to sleep on futex1. Works because */
+    busy_loop(1000, 1);
+    /* Try to wake up the thread with an LLSC event.
+     * It should not wake up in a correct implementation,
+     * but it used to happen in gem5 before it was fixed. */
+    __asm__ __volatile__ (
+        "mov x0, 1;ldxr x0, [%0]; stxr w1, x0, [%0]"
+        :
+        : "r" (ldxr_var) : "x0", "x1", "memory"
+    );
+    /* Wait for thread1 to sleep on futex2. */
+    busy_loop(1000, 1);
+    /* Before it was fixed in gem5, this would wrongly wake a futex2
+     * because the previous futex1 was woken up via LLSC. */
+    futex(&futex1, FUTEX_WAKE, 1, NULL, NULL, 0);
+    assert(!pthread_join(thread, NULL));
+}
diff --git a/src/simple/aarch64/semihost_exit.S b/src/simple/aarch64/semihost_exit.S
new file mode 100644
index 0000000..ace5b30
--- /dev/null
+++ b/src/simple/aarch64/semihost_exit.S
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.global _start
+_start:
+    /* 0x20026 == ADP_Stopped_ApplicationExit */
+    mov x1, 0x26
+    movk x1, 0x2, lsl 16
+    ldr x2, =.Lsemihost_args
+    str x1, [x2, 0]
+
+    /* Exit status code. */
+    mov x0, 0
+    str x0, [x2, 8]
+
+    /* Address of parameter block. */
+    mov x1, x2
+
+    /* SYS_EXIT */
+    mov w0, 0x18
+
+    /* Make the semihosting call. */
+    hlt 0xf000
+.Lsemihost_args:
+    .skip 16
diff --git a/src/simple/bootloader/aarch64.S b/src/simple/bootloader/aarch64.S
new file mode 100644
index 0000000..7cb4b6c
--- /dev/null
+++ b/src/simple/bootloader/aarch64.S
@@ -0,0 +1,6 @@
+.global _start
+_start:
+    ldr x0, =stack_top
+    mov sp, x0
+    mov x0, 0
+    bl main
diff --git a/src/simple/chdir_print.c b/src/simple/chdir_print.c
new file mode 100644
index 0000000..bed844e
--- /dev/null
+++ b/src/simple/chdir_print.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2011-2015 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * # example test compile and run parameters
+ * # Note: the absolute path to the chdir-print binary should be specified
+ * # in the run command even if running from the same folder. This is needed
+ * # because chdir is executed before triggering a clone for the file read,
+ * # and the cloned process won't be able to find the executable if a relative
+ * # path is provided.
+ *
+ * # compile examples
+ * scons --default=X86 ./build/X86/gem5.opt PROTOCOL=MOESI_hammer
+ * scons --default=X86 ./build/X86/gem5.opt PROTOCOL=MESI_Three_Level
+ *
+ * # run parameters
+ * <GEM5_ROOT>/build/X86/gem5.opt <GEM5_ROOT>/configs/example/se.py -c \
+ *   <GEM5_ROOT>/tests/test-progs/chdir-print/chdir-print -n2 --ruby
+ *
+ *
+ * # example successful output for MESI_Three_Level:
+ *
+ * <...>
+ *
+ * **** REAL SIMULATION ****
+ * info: Entering event queue @ 0.  Starting simulation...
+ * warn: Replacement policy updates recently became the responsibility of
+ *   SLICC state machines. Make sure to setMRU() near callbacks in .sm files!
+ * cwd: /proj/research_simu/users/jalsop/gem5-mem_dif_debug/tests/
+ *   test-progs/chdir-print/
+ * cwd: /proc
+ *
+ * <...>
+ *
+ * processor       : 0
+ * vendor_id       : Generic
+ * cpu family      : 0
+ * model           : 0
+ * model name      : Generic
+ * stepping        : 0
+ * cpu MHz         : 2000
+ * cache size:     : 2048K
+ * physical id     : 0
+ * siblings        : 2
+ * core id         : 0
+ * cpu cores       : 2
+ * fpu             : yes
+ * fpu exception   : yes
+ * cpuid level     : 1
+ * wp              : yes
+ * flags           : fpu
+ * cache alignment : 64
+ *
+ * processor       : 1
+ * vendor_id       : Generic
+ * cpu family      : 0
+ * model           : 0
+ * model name      : Generic
+ * stepping        : 0
+ * cpu MHz         : 2000
+ * cache size:     : 2048K
+ * physical id     : 0
+ * siblings        : 2
+ * core id         : 1
+ * cpu cores       : 2
+ * fpu             : yes
+ * fpu exception   : yes
+ * cpuid level     : 1
+ * wp              : yes
+ * flags           : fpu
+ * cache alignment : 64
+ *
+ * SUCCESS
+ * Exiting @ tick 2694923000 because exiting with last active thread context
+ */
+
+#include <assert.h>
+#include <linux/limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+const int BUFFER_SIZE = 64;
+
+// Tests the functionality of RegisterFilesystem
+int main(void)
+{
+    char *cwd = getcwd(NULL, PATH_MAX);
+    printf("cwd: %s\n", cwd);
+    free(cwd);
+
+    assert(!chdir("/proc"));
+
+    cwd = getcwd(NULL, PATH_MAX);
+    printf("cwd: %s\n", cwd);
+    free(cwd);
+
+    FILE *fp;
+    char buffer[BUFFER_SIZE];
+
+    bool found_procline = false;
+    fp = popen("cat cpuinfo", "r");
+    if (fp != NULL) {
+        while (fgets(buffer, BUFFER_SIZE, fp) != NULL) {
+            printf("%s", buffer);
+            if (strstr(buffer, "processor")) {
+                found_procline = true;
+            }
+        }
+        pclose(fp);
+    }
+
+    if (found_procline) {
+        printf("SUCCESS\n");
+        return EXIT_SUCCESS;
+    }
+
+    printf("FAILURE\n");
+    return EXIT_FAILURE;
+}
diff --git a/src/simple/hello.c b/src/simple/hello.c
new file mode 100644
index 0000000..589b06e
--- /dev/null
+++ b/src/simple/hello.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+int main(void) {
+    puts("hello");
+}
diff --git a/src/simple/hello_cpp.cpp b/src/simple/hello_cpp.cpp
new file mode 100644
index 0000000..0cbf750
--- /dev/null
+++ b/src/simple/hello_cpp.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <iostream>
+
+int main() {
+    std::cout << "hello" << std::endl;
+}
diff --git a/src/simple/link.ld b/src/simple/link.ld
new file mode 100644
index 0000000..d3abb9e
--- /dev/null
+++ b/src/simple/link.ld
@@ -0,0 +1,17 @@
+ENTRY(_start)
+SECTIONS
+{
+  .text : {
+    */bootloader.o(.text)
+    *(.text)
+    *(.rodata)
+    *(.data)
+    *(COMMON)
+  }
+  .bss : { *(.bss) }
+  heap_low = .;
+  . = . + 0x1000000;
+  heap_top = .;
+  . = . + 0x1000000;
+  stack_top = .;
+}
diff --git a/src/simple/m5_checkpoint.c b/src/simple/m5_checkpoint.c
new file mode 100644
index 0000000..70bb6e7
--- /dev/null
+++ b/src/simple/m5_checkpoint.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gem5/m5ops.h>
+
+int main(void) {
+    m5_checkpoint(0, 0);
+    m5_exit(0);
+}
diff --git a/src/simple/m5_exit.c b/src/simple/m5_exit.c
new file mode 100644
index 0000000..75932eb
--- /dev/null
+++ b/src/simple/m5_exit.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gem5/m5ops.h>
+
+int main(void) {
+    m5_exit(0);
+}
diff --git a/src/simple/page_access_wrap.cpp b/src/simple/page_access_wrap.cpp
new file mode 100644
index 0000000..8d8b553
--- /dev/null
+++ b/src/simple/page_access_wrap.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/mman.h>
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+
+int main(void)
+{
+    uint64_t page_size = 0x1000;
+    uint64_t num_pages = 0x10000;
+    uint64_t length = page_size * num_pages;
+
+    void *raw = mmap(NULL, length, PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+    uint8_t *mem = reinterpret_cast<uint8_t*>(raw);
+
+    srand(0xABCD);
+
+    uint64_t last_byte = page_size - 1;
+    uint64_t page_boundaries = num_pages - 1;
+
+    for (int i = 0; i < 2000; i++) {
+        uint64_t random_boundary = rand() % page_boundaries;
+        uint64_t boundary_offset = random_boundary * page_size;
+        uint64_t boundary_last_byte = boundary_offset + last_byte;
+        uint32_t *poke = reinterpret_cast<uint32_t*>(mem + boundary_last_byte);
+        printf("%p\n", (void *)poke);
+        __asm__ __volatile__("" : "=r" (*poke) : : );
+    }
+
+    return 0;
+}
diff --git a/src/pthreads/src/test_atomic.cpp b/src/simple/pthread_atomic.cpp
similarity index 98%
rename from src/pthreads/src/test_atomic.cpp
rename to src/simple/pthread_atomic.cpp
index 68c94e4..3fc3aff 100644
--- a/src/pthreads/src/test_atomic.cpp
+++ b/src/simple/pthread_atomic.cpp
@@ -67,7 +67,7 @@
     return nullptr;
 }
 
-int main( int argc, const char* argv[] )
+int main()
 {
     int n_worker_threads = 0;
 
diff --git a/src/pthreads/src/test_pthread_cond.cpp b/src/simple/pthread_cond.cpp
similarity index 98%
rename from src/pthreads/src/test_pthread_cond.cpp
rename to src/simple/pthread_cond.cpp
index 5552f78..ae0d984 100644
--- a/src/pthreads/src/test_pthread_cond.cpp
+++ b/src/simple/pthread_cond.cpp
@@ -80,7 +80,7 @@
     pthread_mutex_unlock( &mutex );
 }
 
-int main( int argc, char* argv[] )
+int main(void)
 {
     size_t n_worker_threads = 0;
 
diff --git a/src/pthreads/src/test_pthread_create_para.cpp b/src/simple/pthread_create_para.cpp
similarity index 98%
rename from src/pthreads/src/test_pthread_create_para.cpp
rename to src/simple/pthread_create_para.cpp
index 1b10c9f..8604c7a 100644
--- a/src/pthreads/src/test_pthread_create_para.cpp
+++ b/src/simple/pthread_create_para.cpp
@@ -62,7 +62,7 @@
     return nullptr;
 }
 
-int main( int argc, const char* argv[] )
+int main()
 {
     int n_worker_threads = 0;
 
diff --git a/src/pthreads/src/test_pthread_create_seq.cpp b/src/simple/pthread_create_seq.cpp
similarity index 98%
rename from src/pthreads/src/test_pthread_create_seq.cpp
rename to src/simple/pthread_create_seq.cpp
index 2a5a571..755d252 100644
--- a/src/pthreads/src/test_pthread_create_seq.cpp
+++ b/src/simple/pthread_create_seq.cpp
@@ -61,7 +61,7 @@
     return nullptr;
 }
 
-int main( int argc, const char* argv[] )
+int main()
 {
     int n_worker_threads = 0;
 
diff --git a/src/pthreads/src/test_pthread_mutex.cpp b/src/simple/pthread_mutex.cpp
similarity index 98%
rename from src/pthreads/src/test_pthread_mutex.cpp
rename to src/simple/pthread_mutex.cpp
index 313539b..80b006d 100644
--- a/src/pthreads/src/test_pthread_mutex.cpp
+++ b/src/simple/pthread_mutex.cpp
@@ -75,7 +75,7 @@
     return nullptr;
 }
 
-int main( int argc, const char* argv[] )
+int main()
 {
     int n_worker_threads = 0;
 
diff --git a/src/pthreads/src/test_std_condition_variable.cpp b/src/simple/pthread_std_condition_variable.cpp
similarity index 96%
rename from src/pthreads/src/test_std_condition_variable.cpp
rename to src/simple/pthread_std_condition_variable.cpp
index b3d162d..de6703c 100644
--- a/src/pthreads/src/test_std_condition_variable.cpp
+++ b/src/simple/pthread_std_condition_variable.cpp
@@ -68,7 +68,7 @@
     cv.notify_all();
 }
 
-int main( int argc, char* argv[] )
+int main()
 {
     size_t n_worker_threads = 0;
 
@@ -86,7 +86,7 @@
     std::cout << n_worker_threads << " threads ready to race...\n";
     go();                       // go!
 
-    for (int i = 0; i < n_worker_threads; ++i) {
+    for (size_t i = 0; i < n_worker_threads; ++i) {
         threads[i].join();
     }
 
diff --git a/src/pthreads/src/test_std_mutex.cpp b/src/simple/pthread_std_mutex.cpp
similarity index 98%
rename from src/pthreads/src/test_std_mutex.cpp
rename to src/simple/pthread_std_mutex.cpp
index e81f60f..dedfd35 100644
--- a/src/pthreads/src/test_std_mutex.cpp
+++ b/src/simple/pthread_std_mutex.cpp
@@ -47,7 +47,7 @@
 
 #define MAX_N_WORKER_THREADS 10
 
-int main( int argc, const char* argv[] )
+int main()
 {
     int n_worker_threads = 0;
 
diff --git a/src/pthreads/src/test_std_thread.cpp b/src/simple/pthread_std_thread.cpp
similarity index 98%
rename from src/pthreads/src/test_std_thread.cpp
rename to src/simple/pthread_std_thread.cpp
index 6634d90..c345fab 100644
--- a/src/pthreads/src/test_std_thread.cpp
+++ b/src/simple/pthread_std_thread.cpp
@@ -48,7 +48,7 @@
 
 #define MAX_N_WORKER_THREADS 10
 
-int main( int argc, char* argv[] )
+int main(void)
 {
     int n_worker_threads = 0;
 
diff --git a/src/simple/stack_print.c b/src/simple/stack_print.c
new file mode 100644
index 0000000..ff431bf
--- /dev/null
+++ b/src/simple/stack_print.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * For use for simulation and test purposes only
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Brandon Potter
+ */
+
+#include <elf.h>
+#include <stdio.h>
+
+int main(int argc, char **argv, char **envp)
+{
+    int i;
+
+    printf("%p: argc: [%d]\n", (void*)&argc, argc);
+    printf("\n");
+
+    for (i = 0; i < argc; i++)
+        printf("%p: argv[%d]: [%s]\n", (void*)&argv[i], i, argv[i]);
+    printf("\n");
+
+    i = 0;
+    while (envp[i] != NULL) {
+        printf("%p: envp[%d]: [%s]\n", (void*)&envp[i], i, envp[i]);
+        i++;
+    }
+    printf("\n");
+
+    Elf64_auxv_t *auxv = (Elf64_auxv_t*)&envp[--i];
+    while (auxv++) {
+        char *type;
+        switch(auxv->a_type) {
+            case AT_IGNORE:
+                type = "AT_IGNORE";
+                break;
+            case AT_EXECFD:
+                type = "AT_EXECFD";
+                break;
+            case AT_PHDR:
+                type = "AT_PHDR";
+                break;
+            case AT_PHENT:
+                type = "AT_PHENT";
+                break;
+            case AT_PHNUM:
+                type = "AT_PHNUM";
+                break;
+            case AT_PAGESZ:
+                type = "AT_PAGESZ";
+                break;
+            case AT_BASE:
+                type = "AT_BASE";
+                break;
+            case AT_FLAGS:
+                type = "AT_FLAGS";
+                break;
+            case AT_ENTRY:
+                type = "AT_ENTRY";
+                break;
+            case AT_NOTELF:
+                type = "AT_NOTELF";
+                break;
+            case AT_UID:
+                type = "AT_UID";
+                break;
+            case AT_EUID:
+                type = "AT_EUID";
+                break;
+            case AT_GID:
+                type = "AT_GID";
+                break;
+            case AT_EGID:
+                type = "AT_EGID";
+                break;
+            case AT_CLKTCK:
+                type = "AT_CLKTCK";
+                break;
+            case AT_PLATFORM:
+                type = "AT_PLATFORM";
+                break;
+            case AT_HWCAP:
+                type = "AT_HWCAP";
+                break;
+            case AT_FPUCW:
+                type = "AT_FPUCW";
+                break;
+            case AT_DCACHEBSIZE:
+                type = "AT_DCACHEBSIZE";
+                break;
+            case AT_ICACHEBSIZE:
+                type = "AT_ICACHEBSIZE";
+                break;
+            case AT_UCACHEBSIZE:
+                type = "AT_UCACHEBSIZE";
+                break;
+            case AT_IGNOREPPC:
+                type = "AT_IGNOREPPC";
+                break;
+            case AT_SECURE:
+                type = "AT_SECURE";
+                break;
+            case AT_BASE_PLATFORM:
+                type = "AT_BASE_PLATFORM";
+                break;
+            case AT_RANDOM:
+                type = "AT_RANDOM";
+                break;
+            case AT_EXECFN:
+                type = "AT_EXECFN";
+                break;
+            case AT_SYSINFO:
+                type = "AT_SYSINFO";
+                break;
+            case AT_SYSINFO_EHDR:
+                type = "AT_SYSINFO_EHDR";
+                break;
+            case AT_L1I_CACHESHAPE:
+                type = "AT_L1I_CACHESHAPE";
+                break;
+            case AT_L1D_CACHESHAPE:
+                type = "AT_L1D_CACHESHAPE";
+                break;
+            case AT_L2_CACHESHAPE:
+                type = "AT_L2_CACHESHAPE";
+                break;
+            case AT_L3_CACHESHAPE:
+                type = "AT_L3_CACHESHAPE";
+                break;
+            case AT_NULL:
+            default:
+                printf("\n");
+                return 0;
+        }
+        printf("%p: %s: [%jx]\n", (void *)auxv, type, (uintmax_t)auxv->a_un.a_val);
+    }
+}
+
diff --git a/src/simple/std_thread.cpp b/src/simple/std_thread.cpp
new file mode 100644
index 0000000..b1e8468
--- /dev/null
+++ b/src/simple/std_thread.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017 Jason Lowe-Power
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met: redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer;
+* redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution;
+* neither the name of the copyright holders nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <iostream>
+#include <thread>
+
+using namespace std;
+
+/*
+ * c = a + b
+ */
+void array_add(int *a, int *b, int *c, int tid, int threads, int num_values)
+{
+    for (int i = tid; i < num_values; i += threads) {
+        c[i] = a[i] + b[i];
+    }
+}
+
+
+int main(int argc, char *argv[])
+{
+    int num_values;
+    if (argc == 1) {
+        num_values = 100;
+    } else if (argc == 2) {
+        num_values = atoi(argv[1]);
+        if (num_values <= 0) {
+            cerr << "Usage: " << argv[0] << " [num_values]" << endl;
+            return 1;
+        }
+    } else {
+        cerr << "Usage: " << argv[0] << " [num_values]" << endl;
+        return 1;
+    }
+
+    int cpus = thread::hardware_concurrency();
+
+    cout << "Running on " << cpus << " cores. ";
+    cout << "with " << num_values << " values" << endl;
+
+    int *a, *b, *c;
+    a = new int[num_values];
+    b = new int[num_values];
+    c = new int[num_values];
+
+    if (!(a && b && c)) {
+        cerr << "Allocation error!" << endl;
+        return 2;
+    }
+
+    for (int i = 0; i < num_values; i++) {
+        a[i] = i;
+        b[i] = num_values - i;
+        c[i] = 0;
+    }
+
+    thread **threads = new thread*[cpus];
+
+    // NOTE: -1 is required for this to work in SE mode.
+    for (int i = 0; i < cpus - 1; i++) {
+        threads[i] = new thread(array_add, a, b, c, i, cpus, num_values);
+    }
+    // Execute the last thread with this thread context to appease SE mode
+    array_add(a, b, c, cpus - 1, cpus, num_values);
+
+    cout << "Waiting for other threads to complete" << endl;
+
+    for (int i = 0; i < cpus - 1; i++) {
+        threads[i]->join();
+    }
+
+    delete[] threads;
+
+    cout << "Validating..." << flush;
+
+    int num_valid = 0;
+    for (int i = 0; i < num_values; i++) {
+        if (c[i] == num_values) {
+            num_valid++;
+        } else {
+            cerr << "c[" << i << "] is wrong.";
+            cerr << " Expected " << num_values;
+            cerr << " Got " << c[i] << "." << endl;
+        }
+    }
+
+    if (num_valid == num_values) {
+        cout << "Success!" << endl;
+        return 0;
+    } else {
+        return 2;
+    }
+}
diff --git a/src/simple/x86_64/mwait.c b/src/simple/x86_64/mwait.c
new file mode 100644
index 0000000..62bf8c8
--- /dev/null
+++ b/src/simple/x86_64/mwait.c
@@ -0,0 +1,75 @@
+// author: Marc Orr
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_TRIES   1000
+
+// Make sure that flags and wait sit in different cache lines
+volatile int flags[10];
+volatile int wait[10];
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void *DoWork1(void *threadid)
+{
+    (void)threadid;
+    flags[0] = flags[0] + 1;
+    wait[0] = 0;
+    pthread_exit(0);
+}
+
+void *DoWork2(void *threadid)
+{
+    (void)threadid;
+    pthread_mutex_lock (&mutex);
+    flags[0] = flags[0] + 1;
+    pthread_mutex_unlock (&mutex);
+    pthread_exit(0);
+}
+
+//////////////////////////////////////////////////////////////////////
+// Program main
+//////////////////////////////////////////////////////////////////////
+int main(void)
+{
+    // stuff for thread
+    pthread_t threads[1];
+
+    // initialize global variables
+    flags[0] = 0;
+    wait[0] = 1;
+
+    // monitor (via gcc intrinsic)
+    __builtin_ia32_monitor ((void *)&flags, 0, 0);
+
+    // invalidate flags in this cpu's cache
+    pthread_create(&threads[0], NULL, DoWork1, NULL);
+    while (wait[0]);
+
+    // launch thread to invalidate address being monitored
+    pthread_create(&threads[0], NULL, DoWork2, NULL);
+
+    // wait for other thread to modify flags
+    int mwait_cnt = 0;
+    do {
+        pthread_mutex_lock (&mutex);
+        if (flags[0] != 2) {
+            pthread_mutex_unlock (&mutex);
+            __builtin_ia32_mwait(0, 0);
+        } else {
+            pthread_mutex_unlock (&mutex);
+        }
+        mwait_cnt++;
+    } while (flags[0] != 2 && mwait_cnt < NUM_TRIES);
+
+    // test may hang if mwait is not working
+    if (flags[0]==2) {
+        printf("mwait regression PASSED, flags[0] = %d\n", flags[0]);
+    } else {
+        printf("mwait regression FAILED, flags[0] = %d\n", flags[0]);
+    }
+
+    return 0;
+}