diff --git a/.gitignore b/.gitignore
index 796b96d1c..189b414f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 /build
+/CMakeLists.txt.user
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef91b561d..2005d74d0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# v0.8.2
+- Fixed L2 cache size detection for AMD CPUs (Bulldozer/Piledriver/Steamroller/Excavator architecture).
+- Fixed gcc 7.1 support.
+
 # v0.8.1
 - Added nicehash support, detects automaticaly by pool URL, for example `cryptonight.eu.nicehash.com:3355` or manually via option `--nicehash`.
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0425d8e99..9bce386cf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,139 +1,168 @@
 cmake_minimum_required(VERSION 3.0)
-project(xmrig C)
+project(xmrig)
 
 option(WITH_LIBCPUID "Use Libcpuid" ON)
 option(WITH_AEON     "CryptoNight-Lite support" ON)
 
 set(HEADERS
-    compat.h
-    algo/cryptonight/cryptonight.h
-    algo/cryptonight/cryptonight_aesni.h
-    algo/cryptonight/cryptonight_softaes.h
-    elist.h
-    xmrig.h
-    version.h
-    options.h
-    cpu.h
-    persistent_memory.h
-    stratum.h
-    stats.h
-    util.h
-    donate.h
+    src/3rdparty/align.h
+    src/App.h
+    src/Console.h
+    src/Cpu.h
+    src/interfaces/IClientListener.h
+    src/interfaces/IJobResultListener.h
+    src/interfaces/IWorker.h
+    src/Mem.h
+    src/net/Client.h
+    src/net/Job.h
+    src/net/JobResult.h
+    src/net/Network.h
+    src/net/Url.h
+    src/Options.h
+    src/Summary.h
+    src/version.h
+    src/workers/DoubleWorker.h
+    src/workers/Handle.h
+    src/workers/SingleWorker.h
+    src/workers/Telemetry.h
+    src/workers/Worker.h
+    src/workers/Workers.h
    )
 
 set(HEADERS_CRYPTO
-    crypto/c_groestl.h
-    crypto/c_blake256.h
-    crypto/c_jh.h
-    crypto/c_skein.h
-   )
-
-set(HEADERS_COMPAT
-    compat/winansi.h
-   )
-
-set(HEADERS_UTILS
-    utils/applog.h
-    utils/threads.h
-    utils/summary.h
+    src/crypto/c_blake256.h
+    src/crypto/c_groestl.h
+    src/crypto/c_jh.h
+    src/crypto/c_keccak.h
+    src/crypto/c_skein.h
+    src/crypto/CryptoNight.h
+    src/crypto/CryptoNight_p.h
+    src/crypto/CryptoNight_test.h
+    src/crypto/groestl_tables.h
+    src/crypto/hash.h
+    src/crypto/skein_port.h
    )
 
 set(SOURCES
-    xmrig.c
-    algo/cryptonight/cryptonight.c
-    algo/cryptonight/cryptonight_av1_aesni.c
-    algo/cryptonight/cryptonight_av2_aesni_double.c
-    algo/cryptonight/cryptonight_av3_softaes.c
-    algo/cryptonight/cryptonight_av4_softaes_double.c
-    util.c
-    options.c
-    stratum.c
-    stats.c
-    memory.c
+    src/App.cpp
+    src/Console.cpp
+    src/Mem.cpp
+    src/net/Client.cpp
+    src/net/Job.cpp
+    src/net/Network.cpp
+    src/net/Url.cpp
+    src/Options.cpp
+    src/Summary.cpp
+    src/workers/DoubleWorker.cpp
+    src/workers/Handle.cpp
+    src/workers/SingleWorker.cpp
+    src/workers/Telemetry.cpp
+    src/workers/Worker.cpp
+    src/workers/Workers.cpp
+    src/xmrig.cpp
    )
 
 set(SOURCES_CRYPTO
-    crypto/c_keccak.c
-    crypto/c_groestl.c
-    crypto/c_blake256.c
-    crypto/c_jh.c
-    crypto/c_skein.c
-    crypto/soft_aes.c
-   )
-
-set(SOURCES_UTILS
-    utils/applog.c
-    utils/summary.c
+    src/crypto/c_keccak.c
+    src/crypto/c_groestl.c
+    src/crypto/c_blake256.c
+    src/crypto/c_jh.c
+    src/crypto/c_skein.c
+    src/crypto/soft_aes.c
+    src/crypto/soft_aes.c
+    src/crypto/CryptoNight.cpp
    )
 
 if (WIN32)
-    set(SOURCES_OS win/cpu_win.c win/memory_win.c win/xmrig_win.c win/app.rc compat/winansi.c)
-    set(EXTRA_LIBS ws2_32)
-    add_definitions(/D_WIN32_WINNT=0x600)
+    set(SOURCES_OS
+        res/app.rc
+        src/3rdparty/winansi.cpp
+        src/3rdparty/winansi.h
+        src/App_win.cpp
+        src/Cpu_win.cpp
+        src/Mem_win.cpp
+        src/net/Network_win.cpp
+        )
+
+    add_definitions(/DWIN32)
+    set(EXTRA_LIBS ws2_32 psapi iphlpapi userenv)
+elseif (APPLE)
+    set(SOURCES_OS
+        src/App_unix.cpp
+        src/Cpu_mac.cpp
+        src/Mem_unix.cpp
+        src/net/Network_mac.cpp
+        )
 else()
-    set(SOURCES_OS unix/cpu_unix.c unix/memory_unix.c unix/xmrig_unix.c)
+    set(SOURCES_OS
+        src/App_unix.cpp
+        src/Cpu_unix.cpp
+        src/Mem_unix.cpp
+        src/net/Network_unix.cpp
+        )
+
     set(EXTRA_LIBS pthread)
 endif()
 
-include_directories(.)
-add_definitions(/DUSE_NATIVE_THREADS)
-add_definitions(/D_GNU_SOURCE)
 add_definitions(/DUNICODE)
+#add_definitions(/DAPP_DEBUG)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
+
+find_package(UV REQUIRED)
 
 if ("${CMAKE_BUILD_TYPE}" STREQUAL "")
     set(CMAKE_BUILD_TYPE Release)
 endif()
 
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -Wno-pointer-to-int-cast")
-set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2")
-#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-2")
-#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fprofile-generate")
-#set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fprofile-use -fprofile-correction")
 
-if (WIN32)
+# https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER_ID.html
+if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
+
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -Wall")
+    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2")
+
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes -Wall -std=c++14 -fno-exceptions -fno-rtti")
+    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -s -funroll-loops -fvariable-expansion-in-unroller -ftree-loop-if-convert-stores -fmerge-all-constants -fbranch-target-load-optimize2")
+
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
+
+    add_definitions(/D_GNU_SOURCE)
+
+    #set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -gdwarf-2")
+
+elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+
+    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Ox /Ot /Oi /MT /GL")
+    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ox /Ot /Oi /MT /GL")
+
+elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
+
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -Wall")
+    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -funroll-loops -fmerge-all-constants")
+
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes -Wall -std=c++14 -fno-exceptions -fno-rtti")
+    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -funroll-loops -fmerge-all-constants")
+
 endif()
 
-include_directories(compat/jansson)
-add_subdirectory(compat/jansson)
-
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
-
-find_package(CURL REQUIRED)
-include_directories(${CURL_INCLUDE_DIRS})
-add_definitions(/DCURL_STATICLIB)
-link_directories(${CURL_LIBRARIES})
-
 if (WITH_LIBCPUID)
-    add_subdirectory(compat/libcpuid)
+    add_subdirectory(src/3rdparty/libcpuid)
 
-    include_directories(compat/libcpuid)
+    include_directories(src/3rdparty/libcpuid)
     set(CPUID_LIB cpuid)
-    set(SOURCES_CPUID cpu.c)
+    set(SOURCES_CPUID src/Cpu.cpp)
 else()
     add_definitions(/DXMRIG_NO_LIBCPUID)
-    set(SOURCES_CPUID cpu_stub.c)
+    set(SOURCES_CPUID src/Cpu_stub.cpp)
 endif()
 
-if (WITH_AEON)
-    set(SOURCES_AEON
-    algo/cryptonight-lite/cryptonight_lite_av1_aesni.c
-    algo/cryptonight-lite/cryptonight_lite_av2_aesni_double.c
-    algo/cryptonight-lite/cryptonight_lite_av3_softaes.c
-    algo/cryptonight-lite/cryptonight_lite_av4_softaes_double.c
-    algo/cryptonight-lite/cryptonight_lite_aesni.h
-    algo/cryptonight-lite/cryptonight_lite_softaes.h
-    )
-else()
-    add_definitions(/DXMRIG_NO_AEON)
-endif()
+include_directories(src)
+include_directories(src/3rdparty)
+include_directories(src/3rdparty/jansson)
+include_directories(${UV_INCLUDE_DIR})
 
-if (CMAKE_SIZEOF_VOID_P EQUAL 8)
-    add_executable(xmrig ${HEADERS} ${HEADERS_CRYPTO} ${SOURCES} ${SOURCES_CRYPTO} ${HEADERS_UTILS} ${SOURCES_UTILS} ${HEADERS_COMPAT} ${SOURCES_COMPAT} ${SOURCES_OS} ${SOURCES_CPUID} ${SOURCES_AEON})
-    target_link_libraries(xmrig jansson curl ${CPUID_LIB} ${EXTRA_LIBS})
-else()
-    add_executable(xmrig32 ${HEADERS} ${HEADERS_CRYPTO} ${SOURCES} ${SOURCES_CRYPTO} ${HEADERS_UTILS} ${SOURCES_UTILS} ${HEADERS_COMPAT} ${SOURCES_COMPAT} ${SOURCES_OS} ${SOURCES_CPUID})
-    target_link_libraries(xmrig32 jansson curl ${CPUID_LIB} ${EXTRA_LIBS})
-endif()
+add_subdirectory(src/3rdparty/jansson)
 
-source_group("HEADERS" FILES ${HEADERS})
+add_executable(xmrig ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO})
+target_link_libraries(xmrig jansson ${UV_LIBRARIES} ${EXTRA_LIBS} ${CPUID_LIB})
diff --git a/README.md b/README.md
index fb3f44e2a..70485e0a6 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Based on cpuminer-multi with heavy optimizations/rewrites and removing a lot of
 * [Download](#download)
 * [Usage](#usage)
 * [Algorithm variations](#algorithm-variations)
-* [Build](#build)
+* [Build](https://github.com/xmrig/xmrig/wiki/Build)
 * [Common Issues](#common-issues)
 * [Other information](#other-information)
 * [Donations](#donations)
@@ -70,42 +70,6 @@ Since version 0.8.0.
 * `--av=3` Software AES implementation.
 * `--av=4` Lower power mode (double hash) of `3`.
 
-## Build
-### Ubuntu (Debian-based distros)
-```
-sudo apt-get install git build-essential cmake libcurl4-openssl-dev
-git clone https://github.com/xmrig/xmrig.git
-cd xmrig
-mkdir build
-cd build
-cmake .. -DCMAKE_BUILD_TYPE=Release
-make
-```
-
-### Windows
-It's complicated, you need [MSYS2](http://www.msys2.org/), custom libcurl build, and of course CMake too.
-
-Necessary MSYS2 packages:
-```
-pacman -Sy
-pacman -S mingw-w64-x86_64-gcc
-pacman -S make
-pacman -S mingw-w64-x86_64-cmake
-pacman -S mingw-w64-x86_64-pkg-config
-```
-Configure options for libcurl:
-```
-./configure --disable-shared --enable-optimize --enable-threaded-resolver --disable-libcurl-option --disable-ares --disable-rt --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-manual --disable-ipv6 --disable-sspi --disable-crypto-auth --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --without-zlib --without-winssl --without-ssl --without-libssh2 --without-nghttp2 --disable-cookies --without-ca-bundle --without-librtmp
-```
-CMake options:
-```
-cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCURL_INCLUDE_DIR="c:\<path>\curl-7.53.1\include" -DCURL_LIBRARY="c:\<path>\curl-7.53.1\lib\.libs"
-```
-
-### Optional features
-`-DWITH_LIBCPUID=OFF` Disable libcpuid. Auto configuration of CPU after this will be very limited.
-`-DWITH_AEON=OFF` Disable CryptoNight-Lite support.
-
 ## Common Issues
 ### HUGE PAGES unavailable
 * Run XMRig as Administrator.
diff --git a/algo/cryptonight-lite/cryptonight_lite_aesni.h b/algo/cryptonight-lite/cryptonight_lite_aesni.h
deleted file mode 100644
index 6c9d15cbf..000000000
--- a/algo/cryptonight-lite/cryptonight_lite_aesni.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __CRYPTONIGHT_LITE_AESNI_H__
-#define __CRYPTONIGHT_LITE_AESNI_H__
-
-#include <x86intrin.h>
-
-
-#define aes_genkey_sub(imm8) \
-    __m128i xout1 = _mm_aeskeygenassist_si128(*xout2, (imm8)); \
-    xout1  = _mm_shuffle_epi32(xout1, 0xFF); \
-    *xout0 = sl_xor(*xout0); \
-    *xout0 = _mm_xor_si128(*xout0, xout1); \
-    xout1  = _mm_aeskeygenassist_si128(*xout0, 0x00);\
-    xout1  = _mm_shuffle_epi32(xout1, 0xAA); \
-    *xout2 = sl_xor(*xout2); \
-    *xout2 = _mm_xor_si128(*xout2, xout1); \
-
-
-// This will shift and xor tmp1 into itself as 4 32-bit vals such as
-// sl_xor(a1 a2 a3 a4) = a1 (a2^a1) (a3^a2^a1) (a4^a3^a2^a1)
-inline __m128i sl_xor(__m128i tmp1)
-{
-    __m128i tmp4;
-    tmp4 = _mm_slli_si128(tmp1, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    tmp4 = _mm_slli_si128(tmp4, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    tmp4 = _mm_slli_si128(tmp4, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    return tmp1;
-}
-
-
-inline void aes_genkey_sub1(__m128i* xout0, __m128i* xout2)
-{
-   aes_genkey_sub(0x1)
-}
-
-
-inline void aes_genkey_sub2(__m128i* xout0, __m128i* xout2)
-{
-   aes_genkey_sub(0x2)
-}
-
-
-inline void aes_genkey_sub4(__m128i* xout0, __m128i* xout2)
-{
-   aes_genkey_sub(0x4)
-}
-
-
-inline void aes_genkey_sub8(__m128i* xout0, __m128i* xout2)
-{
-   aes_genkey_sub(0x8)
-}
-
-
-inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
-{
-    *x0 = _mm_aesenc_si128(*x0, key);
-    *x1 = _mm_aesenc_si128(*x1, key);
-    *x2 = _mm_aesenc_si128(*x2, key);
-    *x3 = _mm_aesenc_si128(*x3, key);
-    *x4 = _mm_aesenc_si128(*x4, key);
-    *x5 = _mm_aesenc_si128(*x5, key);
-    *x6 = _mm_aesenc_si128(*x6, key);
-    *x7 = _mm_aesenc_si128(*x7, key);
-}
-
-
-inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3, __m128i* k4, __m128i* k5, __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
-{
-    __m128i xout0 = _mm_load_si128(memory);
-    __m128i xout2 = _mm_load_si128(memory + 1);
-    *k0 = xout0;
-    *k1 = xout2;
-
-     aes_genkey_sub1(&xout0, &xout2);
-    *k2 = xout0;
-    *k3 = xout2;
-
-     aes_genkey_sub2(&xout0, &xout2);
-    *k4 = xout0;
-    *k5 = xout2;
-
-     aes_genkey_sub4(&xout0, &xout2);
-    *k6 = xout0;
-    *k7 = xout2;
-
-     aes_genkey_sub8(&xout0, &xout2);
-    *k8 = xout0;
-    *k9 = xout2;
-}
-
-
-inline void cn_explode_scratchpad(const __m128i* input, __m128i* output)
-{
-    // This is more than we have registers, compiler will assign 2 keys on the stack
-    __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7;
-    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
-
-    aes_genkey(input, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
-
-    xin0 = _mm_load_si128(input + 4);
-    xin1 = _mm_load_si128(input + 5);
-    xin2 = _mm_load_si128(input + 6);
-    xin3 = _mm_load_si128(input + 7);
-    xin4 = _mm_load_si128(input + 8);
-    xin5 = _mm_load_si128(input + 9);
-    xin6 = _mm_load_si128(input + 10);
-    xin7 = _mm_load_si128(input + 11);
-
-    for (size_t i = 0; __builtin_expect(i < MEMORY_LITE / sizeof(__m128i), 1); i += 8) {
-        aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-
-        _mm_store_si128(output + i + 0, xin0);
-        _mm_store_si128(output + i + 1, xin1);
-        _mm_store_si128(output + i + 2, xin2);
-        _mm_store_si128(output + i + 3, xin3);
-        _mm_store_si128(output + i + 4, xin4);
-        _mm_store_si128(output + i + 5, xin5);
-        _mm_store_si128(output + i + 6, xin6);
-        _mm_store_si128(output + i + 7, xin7);
-    }
-}
-
-
-inline void cn_implode_scratchpad(const __m128i* input, __m128i* output)
-{
-    // This is more than we have registers, compiler will assign 2 keys on the stack
-    __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7;
-    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
-
-    aes_genkey(output + 2, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
-
-    xout0 = _mm_load_si128(output + 4);
-    xout1 = _mm_load_si128(output + 5);
-    xout2 = _mm_load_si128(output + 6);
-    xout3 = _mm_load_si128(output + 7);
-    xout4 = _mm_load_si128(output + 8);
-    xout5 = _mm_load_si128(output + 9);
-    xout6 = _mm_load_si128(output + 10);
-    xout7 = _mm_load_si128(output + 11);
-
-    for (size_t i = 0; __builtin_expect(i < MEMORY_LITE / sizeof(__m128i), 1); i += 8)
-    {
-        xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0);
-        xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1);
-        xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2);
-        xout3 = _mm_xor_si128(_mm_load_si128(input + i + 3), xout3);
-        xout4 = _mm_xor_si128(_mm_load_si128(input + i + 4), xout4);
-        xout5 = _mm_xor_si128(_mm_load_si128(input + i + 5), xout5);
-        xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6);
-        xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7);
-
-        aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-    }
-
-    _mm_store_si128(output + 4, xout0);
-    _mm_store_si128(output + 5, xout1);
-    _mm_store_si128(output + 6, xout2);
-    _mm_store_si128(output + 7, xout3);
-    _mm_store_si128(output + 8, xout4);
-    _mm_store_si128(output + 9, xout5);
-    _mm_store_si128(output + 10, xout6);
-    _mm_store_si128(output + 11, xout7);
-}
-
-
-#if defined(__x86_64__)
-#   define EXTRACT64(X) _mm_cvtsi128_si64(X)
-
-inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi)
-{
-    unsigned __int128 r = (unsigned __int128) a * (unsigned __int128) b;
-    *hi = r >> 64;
-    return (uint64_t) r;
-}
-#elif defined(__i386__)
-#   define HI32(X) \
-    _mm_srli_si128((X), 4)
-
-
-#   define EXTRACT64(X) \
-    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \
-    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32))
-
-inline uint64_t _umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) {
-    // multiplier   = ab = a * 2^32 + b
-    // multiplicand = cd = c * 2^32 + d
-    // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
-    uint64_t a = multiplier >> 32;
-    uint64_t b = multiplier & 0xFFFFFFFF;
-    uint64_t c = multiplicand >> 32;
-    uint64_t d = multiplicand & 0xFFFFFFFF;
-
-    //uint64_t ac = a * c;
-    uint64_t ad = a * d;
-    //uint64_t bc = b * c;
-    uint64_t bd = b * d;
-
-    uint64_t adbc = ad + (b * c);
-    uint64_t adbc_carry = adbc < ad ? 1 : 0;
-
-    // multiplier * multiplicand = product_hi * 2^64 + product_lo
-    uint64_t product_lo = bd + (adbc << 32);
-    uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
-    *product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
-
-    return product_lo;
-}
-#endif
-
-
-#endif /* __CRYPTONIGHT_LITE_AESNI_H__ */
diff --git a/algo/cryptonight-lite/cryptonight_lite_av1_aesni.c b/algo/cryptonight-lite/cryptonight_lite_av1_aesni.c
deleted file mode 100644
index 80110fb2a..000000000
--- a/algo/cryptonight-lite/cryptonight_lite_av1_aesni.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <x86intrin.h>
-#include <string.h>
-
-#include "algo/cryptonight/cryptonight.h"
-#include "cryptonight_lite_aesni.h"
-#include "crypto/c_keccak.h"
-
-
-void cryptonight_lite_av1_aesni(const void *restrict input, size_t size, void *restrict output, struct cryptonight_ctx *restrict ctx)
-{
-    keccak((const uint8_t *) input, size, ctx->state0, 200);
-
-    cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory);
-
-    const uint8_t* l0 = ctx->memory;
-    uint64_t* h0 = (uint64_t*) ctx->state0;
-
-    uint64_t al0 = h0[0] ^ h0[4];
-    uint64_t ah0 = h0[1] ^ h0[5];
-    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
-
-    uint64_t idx0 = h0[0] ^ h0[4];
-
-    for (size_t i = 0; __builtin_expect(i < 0x40000, 1); i++) {
-        __m128i cx;
-        cx = _mm_load_si128((__m128i *) &l0[idx0 & 0xFFFF0]);
-        cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0));
-
-        _mm_store_si128((__m128i *) &l0[idx0 & 0xFFFF0], _mm_xor_si128(bx0, cx));
-        idx0 = EXTRACT64(cx);
-        bx0 = cx;
-
-        uint64_t hi, lo, cl, ch;
-        cl = ((uint64_t*) &l0[idx0 & 0xFFFF0])[0];
-        ch = ((uint64_t*) &l0[idx0 & 0xFFFF0])[1];
-        lo = _umul128(idx0, cl, &hi);
-
-        al0 += hi;
-        ah0 += lo;
-
-        ((uint64_t*)&l0[idx0 & 0xFFFF0])[0] = al0;
-        ((uint64_t*)&l0[idx0 & 0xFFFF0])[1] = ah0;
-
-        ah0 ^= ch;
-        al0 ^= cl;
-        idx0 = al0;
-    }
-
-    cn_implode_scratchpad((__m128i*) ctx->memory, (__m128i*) ctx->state0);
-
-    keccakf(h0, 24);
-    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output);
-}
diff --git a/algo/cryptonight-lite/cryptonight_lite_av2_aesni_double.c b/algo/cryptonight-lite/cryptonight_lite_av2_aesni_double.c
deleted file mode 100644
index 055435c6a..000000000
--- a/algo/cryptonight-lite/cryptonight_lite_av2_aesni_double.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <x86intrin.h>
-#include <string.h>
-
-#include "algo/cryptonight/cryptonight.h"
-#include "cryptonight_lite_aesni.h"
-#include "crypto/c_keccak.h"
-
-
-void cryptonight_lite_av2_aesni_double(const void *restrict input, size_t size, void *restrict output, struct cryptonight_ctx *restrict ctx)
-{
-    keccak((const uint8_t *) input,        size, ctx->state0, 200);
-    keccak((const uint8_t *) input + size, size, ctx->state1, 200);
-
-    const uint8_t* l0 = ctx->memory;
-    const uint8_t* l1 = ctx->memory + MEMORY_LITE;
-    uint64_t* h0 = (uint64_t*) ctx->state0;
-    uint64_t* h1 = (uint64_t*) ctx->state1;
-
-    cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
-    cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
-
-    uint64_t al0 = h0[0] ^ h0[4];
-    uint64_t al1 = h1[0] ^ h1[4];
-    uint64_t ah0 = h0[1] ^ h0[5];
-    uint64_t ah1 = h1[1] ^ h1[5];
-
-    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
-    __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
-
-    uint64_t idx0 = h0[0] ^ h0[4];
-    uint64_t idx1 = h1[0] ^ h1[4];
-
-    for (size_t i = 0; __builtin_expect(i < 0x40000, 1); i++) {
-        __m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & 0xFFFF0]);
-        __m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & 0xFFFF0]);
-
-        cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0));
-        cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1));
-
-        _mm_store_si128((__m128i *) &l0[idx0 & 0xFFFF0], _mm_xor_si128(bx0, cx0));
-        _mm_store_si128((__m128i *) &l1[idx1 & 0xFFFF0], _mm_xor_si128(bx1, cx1));
-
-        idx0 = EXTRACT64(cx0);
-        idx1 = EXTRACT64(cx1);
-
-        bx0 = cx0;
-        bx1 = cx1;
-
-        uint64_t hi, lo, cl, ch;
-        cl = ((uint64_t*) &l0[idx0 & 0xFFFF0])[0];
-        ch = ((uint64_t*) &l0[idx0 & 0xFFFF0])[1];
-        lo = _umul128(idx0, cl, &hi);
-
-        al0 += hi;
-        ah0 += lo;
-
-        ((uint64_t*) &l0[idx0 & 0xFFFF0])[0] = al0;
-        ((uint64_t*) &l0[idx0 & 0xFFFF0])[1] = ah0;
-
-        ah0 ^= ch;
-        al0 ^= cl;
-        idx0 = al0;
-
-        cl = ((uint64_t*) &l1[idx1 & 0xFFFF0])[0];
-        ch = ((uint64_t*) &l1[idx1 & 0xFFFF0])[1];
-        lo = _umul128(idx1, cl, &hi);
-
-        al1 += hi;
-        ah1 += lo;
-
-        ((uint64_t*) &l1[idx1 & 0xFFFF0])[0] = al1;
-        ((uint64_t*) &l1[idx1 & 0xFFFF0])[1] = ah1;
-
-        ah1 ^= ch;
-        al1 ^= cl;
-        idx1 = al1;
-    }
-
-    cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
-    cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
-
-    keccakf(h0, 24);
-    keccakf(h1, 24);
-
-    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output);
-    extra_hashes[ctx->state1[0] & 3](ctx->state1, 200, (char*) output + 32);
-}
diff --git a/algo/cryptonight-lite/cryptonight_lite_av3_softaes.c b/algo/cryptonight-lite/cryptonight_lite_av3_softaes.c
deleted file mode 100644
index 3dec6e335..000000000
--- a/algo/cryptonight-lite/cryptonight_lite_av3_softaes.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <x86intrin.h>
-#include <string.h>
-
-#include "algo/cryptonight/cryptonight.h"
-#include "cryptonight_lite_softaes.h"
-#include "crypto/c_keccak.h"
-
-
-void cryptonight_lite_av3_softaes(const void *restrict input, size_t size, void *restrict output, struct cryptonight_ctx *restrict ctx)
-{
-    keccak((const uint8_t *) input, size, ctx->state0, 200);
-
-    cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory);
-
-    const uint8_t* l0 = ctx->memory;
-    uint64_t* h0 = (uint64_t*) ctx->state0;
-
-    uint64_t al0 = h0[0] ^ h0[4];
-    uint64_t ah0 = h0[1] ^ h0[5];
-    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
-
-    uint64_t idx0 = h0[0] ^ h0[4];
-
-    for (size_t i = 0; __builtin_expect(i < 0x40000, 1); i++) {
-        __m128i cx;
-        cx = _mm_load_si128((__m128i *)&l0[idx0 & 0xFFFF0]);
-        cx = soft_aesenc(cx, _mm_set_epi64x(ah0, al0));
-
-        _mm_store_si128((__m128i *)&l0[idx0 & 0xFFFF0], _mm_xor_si128(bx0, cx));
-        idx0 = EXTRACT64(cx);
-        bx0 = cx;
-
-        uint64_t hi, lo, cl, ch;
-        cl = ((uint64_t*)&l0[idx0 & 0xFFFF0])[0];
-        ch = ((uint64_t*)&l0[idx0 & 0xFFFF0])[1];
-        lo = _umul128(idx0, cl, &hi);
-
-        al0 += hi;
-        ah0 += lo;
-
-        ((uint64_t*)&l0[idx0 & 0xFFFF0])[0] = al0;
-        ((uint64_t*)&l0[idx0 & 0xFFFF0])[1] = ah0;
-
-        ah0 ^= ch;
-        al0 ^= cl;
-        idx0 = al0;
-    }
-
-    cn_implode_scratchpad((__m128i*) ctx->memory, (__m128i*) ctx->state0);
-
-    keccakf(h0, 24);
-    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output);
-}
diff --git a/algo/cryptonight-lite/cryptonight_lite_av4_softaes_double.c b/algo/cryptonight-lite/cryptonight_lite_av4_softaes_double.c
deleted file mode 100644
index 873b8cac0..000000000
--- a/algo/cryptonight-lite/cryptonight_lite_av4_softaes_double.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <x86intrin.h>
-#include <string.h>
-
-#include "algo/cryptonight/cryptonight.h"
-#include "cryptonight_lite_softaes.h"
-#include "crypto/c_keccak.h"
-
-
-void cryptonight_lite_av4_softaes_double(const void *restrict input, size_t size, void *restrict output, struct cryptonight_ctx *restrict ctx)
-{
-    keccak((const uint8_t *) input,        size, ctx->state0, 200);
-    keccak((const uint8_t *) input + size, size, ctx->state1, 200);
-
-    const uint8_t* l0 = ctx->memory;
-    const uint8_t* l1 = ctx->memory + MEMORY_LITE;
-    uint64_t* h0 = (uint64_t*) ctx->state0;
-    uint64_t* h1 = (uint64_t*) ctx->state1;
-
-    cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
-    cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
-
-    uint64_t al0 = h0[0] ^ h0[4];
-    uint64_t al1 = h1[0] ^ h1[4];
-    uint64_t ah0 = h0[1] ^ h0[5];
-    uint64_t ah1 = h1[1] ^ h1[5];
-
-    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
-    __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
-
-    uint64_t idx0 = h0[0] ^ h0[4];
-    uint64_t idx1 = h1[0] ^ h1[4];
-
-    for (size_t i = 0; __builtin_expect(i < 0x40000, 1); i++) {
-        __m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & 0xFFFF0]);
-        __m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & 0xFFFF0]);
-
-        cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
-        cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
-
-        _mm_store_si128((__m128i *) &l0[idx0 & 0xFFFF0], _mm_xor_si128(bx0, cx0));
-        _mm_store_si128((__m128i *) &l1[idx1 & 0xFFFF0], _mm_xor_si128(bx1, cx1));
-
-        idx0 = EXTRACT64(cx0);
-        idx1 = EXTRACT64(cx1);
-
-        bx0 = cx0;
-        bx1 = cx1;
-
-        uint64_t hi, lo, cl, ch;
-        cl = ((uint64_t*) &l0[idx0 & 0xFFFF0])[0];
-        ch = ((uint64_t*) &l0[idx0 & 0xFFFF0])[1];
-        lo = _umul128(idx0, cl, &hi);
-
-        al0 += hi;
-        ah0 += lo;
-
-        ((uint64_t*) &l0[idx0 & 0xFFFF0])[0] = al0;
-        ((uint64_t*) &l0[idx0 & 0xFFFF0])[1] = ah0;
-
-        ah0 ^= ch;
-        al0 ^= cl;
-        idx0 = al0;
-
-        cl = ((uint64_t*) &l1[idx1 & 0xFFFF0])[0];
-        ch = ((uint64_t*) &l1[idx1 & 0xFFFF0])[1];
-        lo = _umul128(idx1, cl, &hi);
-
-        al1 += hi;
-        ah1 += lo;
-
-        ((uint64_t*) &l1[idx1 & 0xFFFF0])[0] = al1;
-        ((uint64_t*) &l1[idx1 & 0xFFFF0])[1] = ah1;
-
-        ah1 ^= ch;
-        al1 ^= cl;
-        idx1 = al1;
-    }
-
-    cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
-    cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
-
-    keccakf(h0, 24);
-    keccakf(h1, 24);
-
-    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output);
-    extra_hashes[ctx->state1[0] & 3](ctx->state1, 200, (char*) output + 32);
-}
diff --git a/algo/cryptonight-lite/cryptonight_lite_softaes.h b/algo/cryptonight-lite/cryptonight_lite_softaes.h
deleted file mode 100644
index 15a0a574e..000000000
--- a/algo/cryptonight-lite/cryptonight_lite_softaes.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __CRYPTONIGHT_LITE_SOFTAES_H__
-#define __CRYPTONIGHT_LITE_SOFTAES_H__
-
-#include <x86intrin.h>
-
-extern __m128i soft_aesenc(__m128i in, __m128i key);
-extern __m128i soft_aeskeygenassist(__m128i key, uint8_t rcon);
-
-
-// This will shift and xor tmp1 into itself as 4 32-bit vals such as
-// sl_xor(a1 a2 a3 a4) = a1 (a2^a1) (a3^a2^a1) (a4^a3^a2^a1)
-inline __m128i sl_xor(__m128i tmp1)
-{
-    __m128i tmp4;
-    tmp4 = _mm_slli_si128(tmp1, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    tmp4 = _mm_slli_si128(tmp4, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    tmp4 = _mm_slli_si128(tmp4, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    return tmp1;
-}
-
-
-inline void aes_genkey_sub(__m128i* xout0, __m128i* xout2, uint8_t rcon)
-{
-    __m128i xout1 = soft_aeskeygenassist(*xout2, rcon);
-    xout1  = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
-    *xout0 = sl_xor(*xout0);
-    *xout0 = _mm_xor_si128(*xout0, xout1);
-    xout1  = soft_aeskeygenassist(*xout0, 0x00);
-    xout1  = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
-    *xout2 = sl_xor(*xout2);
-    *xout2 = _mm_xor_si128(*xout2, xout1);
-}
-
-
-inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
-{
-    *x0 = soft_aesenc(*x0, key);
-    *x1 = soft_aesenc(*x1, key);
-    *x2 = soft_aesenc(*x2, key);
-    *x3 = soft_aesenc(*x3, key);
-    *x4 = soft_aesenc(*x4, key);
-    *x5 = soft_aesenc(*x5, key);
-    *x6 = soft_aesenc(*x6, key);
-    *x7 = soft_aesenc(*x7, key);
-}
-
-
-inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3, __m128i* k4, __m128i* k5, __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
-{
-    __m128i xout0 = _mm_load_si128(memory);
-    __m128i xout2 = _mm_load_si128(memory + 1);
-    *k0 = xout0;
-    *k1 = xout2;
-
-    aes_genkey_sub(&xout0, &xout2, 0x1);
-    *k2 = xout0;
-    *k3 = xout2;
-
-    aes_genkey_sub(&xout0, &xout2, 0x2);
-    *k4 = xout0;
-    *k5 = xout2;
-
-    aes_genkey_sub(&xout0, &xout2, 0x4);
-    *k6 = xout0;
-    *k7 = xout2;
-
-    aes_genkey_sub(&xout0, &xout2, 0x8);
-    *k8 = xout0;
-    *k9 = xout2;
-}
-
-
-inline void cn_explode_scratchpad(const __m128i* input, __m128i* output)
-{
-    // This is more than we have registers, compiler will assign 2 keys on the stack
-    __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7;
-    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
-
-    aes_genkey(input, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
-
-    xin0 = _mm_load_si128(input + 4);
-    xin1 = _mm_load_si128(input + 5);
-    xin2 = _mm_load_si128(input + 6);
-    xin3 = _mm_load_si128(input + 7);
-    xin4 = _mm_load_si128(input + 8);
-    xin5 = _mm_load_si128(input + 9);
-    xin6 = _mm_load_si128(input + 10);
-    xin7 = _mm_load_si128(input + 11);
-
-    for (size_t i = 0; i < MEMORY_LITE / sizeof(__m128i); i += 8) {
-        aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-
-        _mm_store_si128(output + i + 0, xin0);
-        _mm_store_si128(output + i + 1, xin1);
-        _mm_store_si128(output + i + 2, xin2);
-        _mm_store_si128(output + i + 3, xin3);
-        _mm_store_si128(output + i + 4, xin4);
-        _mm_store_si128(output + i + 5, xin5);
-        _mm_store_si128(output + i + 6, xin6);
-        _mm_store_si128(output + i + 7, xin7);
-    }
-}
-
-
-inline void cn_implode_scratchpad(const __m128i* input, __m128i* output)
-{
-    // This is more than we have registers, compiler will assign 2 keys on the stack
-    __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7;
-    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
-
-    aes_genkey(output + 2, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
-
-    xout0 = _mm_load_si128(output + 4);
-    xout1 = _mm_load_si128(output + 5);
-    xout2 = _mm_load_si128(output + 6);
-    xout3 = _mm_load_si128(output + 7);
-    xout4 = _mm_load_si128(output + 8);
-    xout5 = _mm_load_si128(output + 9);
-    xout6 = _mm_load_si128(output + 10);
-    xout7 = _mm_load_si128(output + 11);
-
-    for (size_t i = 0; __builtin_expect(i < MEMORY_LITE / sizeof(__m128i), 1); i += 8)
-    {
-        xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0);
-        xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1);
-        xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2);
-        xout3 = _mm_xor_si128(_mm_load_si128(input + i + 3), xout3);
-        xout4 = _mm_xor_si128(_mm_load_si128(input + i + 4), xout4);
-        xout5 = _mm_xor_si128(_mm_load_si128(input + i + 5), xout5);
-        xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6);
-        xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7);
-
-        aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-    }
-
-    _mm_store_si128(output + 4, xout0);
-    _mm_store_si128(output + 5, xout1);
-    _mm_store_si128(output + 6, xout2);
-    _mm_store_si128(output + 7, xout3);
-    _mm_store_si128(output + 8, xout4);
-    _mm_store_si128(output + 9, xout5);
-    _mm_store_si128(output + 10, xout6);
-    _mm_store_si128(output + 11, xout7);
-}
-
-
-#if defined(__x86_64__)
-#   define EXTRACT64(X) _mm_cvtsi128_si64(X)
-
-inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi)
-{
-    unsigned __int128 r = (unsigned __int128) a * (unsigned __int128) b;
-    *hi = r >> 64;
-    return (uint64_t) r;
-}
-#elif defined(__i386__)
-#   define HI32(X) \
-    _mm_srli_si128((X), 4)
-
-
-#   define EXTRACT64(X) \
-    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \
-    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32))
-
-inline uint64_t _umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) {
-    // multiplier   = ab = a * 2^32 + b
-    // multiplicand = cd = c * 2^32 + d
-    // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
-    uint64_t a = multiplier >> 32;
-    uint64_t b = multiplier & 0xFFFFFFFF;
-    uint64_t c = multiplicand >> 32;
-    uint64_t d = multiplicand & 0xFFFFFFFF;
-
-    //uint64_t ac = a * c;
-    uint64_t ad = a * d;
-    //uint64_t bc = b * c;
-    uint64_t bd = b * d;
-
-    uint64_t adbc = ad + (b * c);
-    uint64_t adbc_carry = adbc < ad ? 1 : 0;
-
-    // multiplier * multiplicand = product_hi * 2^64 + product_lo
-    uint64_t product_lo = bd + (adbc << 32);
-    uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
-    *product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
-
-    return product_lo;
-}
-#endif
-
-
-#endif /* __CRYPTONIGHT_LITE_SOFTAES_H__ */
diff --git a/algo/cryptonight/cryptonight.c b/algo/cryptonight/cryptonight.c
deleted file mode 100644
index 730187280..000000000
--- a/algo/cryptonight/cryptonight.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <mm_malloc.h>
-
-#ifndef BUILD_TEST
-#   include "xmrig.h"
-#endif
-
-#include "crypto/c_groestl.h"
-#include "crypto/c_blake256.h"
-#include "crypto/c_jh.h"
-#include "crypto/c_skein.h"
-#include "cryptonight.h"
-#include "options.h"
-
-
-const static char test_input[152] = {
-    0x01, 0x00, 0xFB, 0x8E, 0x8A, 0xC8, 0x05, 0x89, 0x93, 0x23, 0x37, 0x1B, 0xB7, 0x90, 0xDB, 0x19,
-    0x21, 0x8A, 0xFD, 0x8D, 0xB8, 0xE3, 0x75, 0x5D, 0x8B, 0x90, 0xF3, 0x9B, 0x3D, 0x55, 0x06, 0xA9,
-    0xAB, 0xCE, 0x4F, 0xA9, 0x12, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x81, 0x46, 0xD4, 0x9F,
-    0xA9, 0x3E, 0xE7, 0x24, 0xDE, 0xB5, 0x7D, 0x12, 0xCB, 0xC6, 0xC6, 0xF3, 0xB9, 0x24, 0xD9, 0x46,
-    0x12, 0x7C, 0x7A, 0x97, 0x41, 0x8F, 0x93, 0x48, 0x82, 0x8F, 0x0F, 0x02,
-    0x03, 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00,
-    0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B,
-    0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62,
-    0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92,
-    0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01
-};
-
-
-const static char test_output0[64] = {
-    0x1B, 0x60, 0x6A, 0x3F, 0x4A, 0x07, 0xD6, 0x48, 0x9A, 0x1B, 0xCD, 0x07, 0x69, 0x7B, 0xD1, 0x66,
-    0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F,
-    0x1A, 0x3F, 0xFB, 0xEE, 0x90, 0x9B, 0x42, 0x0D, 0x91, 0xF7, 0xBE, 0x6E, 0x5F, 0xB5, 0x6D, 0xB7,
-    0x1B, 0x31, 0x10, 0xD8, 0x86, 0x01, 0x1E, 0x87, 0x7E, 0xE5, 0x78, 0x6A, 0xFD, 0x08, 0x01, 0x00
-};
-
-
-void cryptonight_av1_aesni(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx);
-void cryptonight_av2_aesni_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx);
-void cryptonight_av3_softaes(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx);
-void cryptonight_av4_softaes_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx);
-
-#ifndef XMRIG_NO_AEON
-const static char test_output1[64] = {
-    0x28, 0xA2, 0x2B, 0xAD, 0x3F, 0x93, 0xD1, 0x40, 0x8F, 0xCA, 0x47, 0x2E, 0xB5, 0xAD, 0x1C, 0xBE,
-    0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD,
-    0x36, 0x95, 0xB4, 0xB5, 0x3B, 0xB0, 0x03, 0x58, 0xB0, 0xAD, 0x38, 0xDC, 0x16, 0x0F, 0xEB, 0x9E,
-    0x00, 0x4E, 0xEC, 0xE0, 0x9B, 0x83, 0xA7, 0x2E, 0xF6, 0xBA, 0x98, 0x64, 0xD3, 0x51, 0x0C, 0x88,
-};
-
-void cryptonight_lite_av1_aesni(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx);
-void cryptonight_lite_av2_aesni_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx);
-void cryptonight_lite_av3_softaes(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx);
-void cryptonight_lite_av4_softaes_double(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx);
-#endif
-
-void (*cryptonight_hash_ctx)(const void* input, size_t size, void* output, struct cryptonight_ctx* ctx) = NULL;
-
-
-static bool self_test() {
-    if (cryptonight_hash_ctx == NULL) {
-        return false;
-    }
-
-    char output[64];
-
-    struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) _mm_malloc(sizeof(struct cryptonight_ctx), 16);
-    ctx->memory = (uint8_t *) _mm_malloc(MEMORY * 2, 16);
-
-    cryptonight_hash_ctx(test_input, 76, output, ctx);
-
-    _mm_free(ctx->memory);
-    _mm_free(ctx);
-
-#   ifndef XMRIG_NO_AEON
-    if (opt_algo == ALGO_CRYPTONIGHT_LITE) {
-        return memcmp(output, test_output1, (opt_double_hash ? 64 : 32)) == 0;
-    }
-#   endif
-
-    return memcmp(output, test_output0, (opt_double_hash ? 64 : 32)) == 0;
-}
-
-
-#ifndef XMRIG_NO_AEON
-bool cryptonight_lite_init(int variant) {
-    switch (variant) {
-        case AEON_AV1_AESNI:
-            cryptonight_hash_ctx = cryptonight_lite_av1_aesni;
-            break;
-
-        case AEON_AV2_AESNI_DOUBLE:
-            opt_double_hash = true;
-            cryptonight_hash_ctx = cryptonight_lite_av2_aesni_double;
-            break;
-
-        case AEON_AV3_SOFT_AES:
-            cryptonight_hash_ctx = cryptonight_lite_av3_softaes;
-            break;
-
-        case AEON_AV4_SOFT_AES_DOUBLE:
-            opt_double_hash = true;
-            cryptonight_hash_ctx = cryptonight_lite_av4_softaes_double;
-            break;
-
-        default:
-            break;
-    }
-
-    return self_test();
-}
-#endif
-
-
-bool cryptonight_init(int variant)
-{
-#   ifndef XMRIG_NO_AEON
-    if (opt_algo == ALGO_CRYPTONIGHT_LITE) {
-        return cryptonight_lite_init(variant);
-    }
-#   endif
-
-    switch (variant) {
-        case XMR_AV1_AESNI:
-            cryptonight_hash_ctx = cryptonight_av1_aesni;
-            break;
-
-        case XMR_AV2_AESNI_DOUBLE:
-            opt_double_hash = true;
-            cryptonight_hash_ctx = cryptonight_av2_aesni_double;
-            break;
-
-        case XMR_AV3_SOFT_AES:
-            cryptonight_hash_ctx = cryptonight_av3_softaes;
-            break;
-
-        case XMR_AV4_SOFT_AES_DOUBLE:
-            opt_double_hash = true;
-            cryptonight_hash_ctx = cryptonight_av4_softaes_double;
-            break;
-
-        default:
-            break;
-    }
-
-    return self_test();
-}
-
-
-static inline void do_blake_hash(const void* input, size_t len, char* output) {
-    blake256_hash((uint8_t*)output, input, len);
-}
-
-
-static inline void do_groestl_hash(const void* input, size_t len, char* output) {
-    groestl(input, len * 8, (uint8_t*)output);
-}
-
-
-static inline void do_jh_hash(const void* input, size_t len, char* output) {
-    jh_hash(32 * 8, input, 8 * len, (uint8_t*)output);
-}
-
-
-static inline void do_skein_hash(const void* input, size_t len, char* output) {
-    skein_hash(8 * 32, input, 8 * len, (uint8_t*)output);
-}
-
-
-void (* const extra_hashes[4])(const void *, size_t, char *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash};
-
-
-#ifndef BUILD_TEST
-int scanhash_cryptonight(int thr_id, uint32_t *hash, uint32_t *restrict blob, size_t blob_size, uint32_t target, uint32_t max_nonce, unsigned long *restrict hashes_done, struct cryptonight_ctx *restrict ctx) {
-    uint32_t *nonceptr = (uint32_t*) (((char*) blob) + 39);
-
-    do {
-        cryptonight_hash_ctx(blob, blob_size, hash, ctx);
-        (*hashes_done)++;
-
-        if (unlikely(hash[7] < target)) {
-            return 1;
-        }
-
-        (*nonceptr)++;
-    } while (likely(((*nonceptr) < max_nonce && !work_restart[thr_id].restart)));
-
-    return 0;
-}
-
-
-int scanhash_cryptonight_double(int thr_id, uint32_t *hash, uint8_t *restrict blob, size_t blob_size, uint32_t target, uint32_t max_nonce, unsigned long *restrict hashes_done, struct cryptonight_ctx *restrict ctx) {
-    int rc = 0;
-    uint32_t *nonceptr0 = (uint32_t*) (((char*) blob) + 39);
-    uint32_t *nonceptr1 = (uint32_t*) (((char*) blob) + 39 + blob_size);
-
-    do {
-        cryptonight_hash_ctx(blob, blob_size, hash, ctx);
-        (*hashes_done) += 2;
-
-        if (unlikely(hash[7] < target)) {
-            return rc |= 1;
-        }
-
-        if (unlikely(hash[15] < target)) {
-            return rc |= 2;
-        }
-
-        if (rc) {
-            break;
-        }
-
-        (*nonceptr0)++;
-        (*nonceptr1)++;
-    } while (likely(((*nonceptr0) < max_nonce && !work_restart[thr_id].restart)));
-
-    return rc;
-}
-#endif
diff --git a/algo/cryptonight/cryptonight_aesni.h b/algo/cryptonight/cryptonight_aesni.h
deleted file mode 100644
index 30ad690a5..000000000
--- a/algo/cryptonight/cryptonight_aesni.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __CRYPTONIGHT_AESNI_H__
-#define __CRYPTONIGHT_AESNI_H__
-
-#include <x86intrin.h>
-
-
-#define aes_genkey_sub(imm8) \
-    __m128i xout1 = _mm_aeskeygenassist_si128(*xout2, (imm8)); \
-    xout1  = _mm_shuffle_epi32(xout1, 0xFF); \
-    *xout0 = sl_xor(*xout0); \
-    *xout0 = _mm_xor_si128(*xout0, xout1); \
-    xout1  = _mm_aeskeygenassist_si128(*xout0, 0x00);\
-    xout1  = _mm_shuffle_epi32(xout1, 0xAA); \
-    *xout2 = sl_xor(*xout2); \
-    *xout2 = _mm_xor_si128(*xout2, xout1); \
-
-
-// This will shift and xor tmp1 into itself as 4 32-bit vals such as
-// sl_xor(a1 a2 a3 a4) = a1 (a2^a1) (a3^a2^a1) (a4^a3^a2^a1)
-inline __m128i sl_xor(__m128i tmp1)
-{
-    __m128i tmp4;
-    tmp4 = _mm_slli_si128(tmp1, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    tmp4 = _mm_slli_si128(tmp4, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    tmp4 = _mm_slli_si128(tmp4, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    return tmp1;
-}
-
-
-inline void aes_genkey_sub1(__m128i* xout0, __m128i* xout2)
-{
-   aes_genkey_sub(0x1)
-}
-
-
-inline void aes_genkey_sub2(__m128i* xout0, __m128i* xout2)
-{
-   aes_genkey_sub(0x2)
-}
-
-
-inline void aes_genkey_sub4(__m128i* xout0, __m128i* xout2)
-{
-   aes_genkey_sub(0x4)
-}
-
-
-inline void aes_genkey_sub8(__m128i* xout0, __m128i* xout2)
-{
-   aes_genkey_sub(0x8)
-}
-
-
-inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
-{
-    *x0 = _mm_aesenc_si128(*x0, key);
-    *x1 = _mm_aesenc_si128(*x1, key);
-    *x2 = _mm_aesenc_si128(*x2, key);
-    *x3 = _mm_aesenc_si128(*x3, key);
-    *x4 = _mm_aesenc_si128(*x4, key);
-    *x5 = _mm_aesenc_si128(*x5, key);
-    *x6 = _mm_aesenc_si128(*x6, key);
-    *x7 = _mm_aesenc_si128(*x7, key);
-}
-
-
-inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3, __m128i* k4, __m128i* k5, __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
-{
-    __m128i xout0 = _mm_load_si128(memory);
-    __m128i xout2 = _mm_load_si128(memory + 1);
-    *k0 = xout0;
-    *k1 = xout2;
-
-     aes_genkey_sub1(&xout0, &xout2);
-    *k2 = xout0;
-    *k3 = xout2;
-
-     aes_genkey_sub2(&xout0, &xout2);
-    *k4 = xout0;
-    *k5 = xout2;
-
-     aes_genkey_sub4(&xout0, &xout2);
-    *k6 = xout0;
-    *k7 = xout2;
-
-     aes_genkey_sub8(&xout0, &xout2);
-    *k8 = xout0;
-    *k9 = xout2;
-}
-
-
-inline void cn_explode_scratchpad(const __m128i* input, __m128i* output)
-{
-    // This is more than we have registers, compiler will assign 2 keys on the stack
-    __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7;
-    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
-
-    aes_genkey(input, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
-
-    xin0 = _mm_load_si128(input + 4);
-    xin1 = _mm_load_si128(input + 5);
-    xin2 = _mm_load_si128(input + 6);
-    xin3 = _mm_load_si128(input + 7);
-    xin4 = _mm_load_si128(input + 8);
-    xin5 = _mm_load_si128(input + 9);
-    xin6 = _mm_load_si128(input + 10);
-    xin7 = _mm_load_si128(input + 11);
-
-    for (size_t i = 0; __builtin_expect(i < MEMORY / sizeof(__m128i), 1); i += 8) {
-        aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-
-        _mm_store_si128(output + i + 0, xin0);
-        _mm_store_si128(output + i + 1, xin1);
-        _mm_store_si128(output + i + 2, xin2);
-        _mm_store_si128(output + i + 3, xin3);
-        _mm_store_si128(output + i + 4, xin4);
-        _mm_store_si128(output + i + 5, xin5);
-        _mm_store_si128(output + i + 6, xin6);
-        _mm_store_si128(output + i + 7, xin7);
-    }
-}
-
-
-inline void cn_implode_scratchpad(const __m128i* input, __m128i* output)
-{
-    // This is more than we have registers, compiler will assign 2 keys on the stack
-    __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7;
-    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
-
-    aes_genkey(output + 2, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
-
-    xout0 = _mm_load_si128(output + 4);
-    xout1 = _mm_load_si128(output + 5);
-    xout2 = _mm_load_si128(output + 6);
-    xout3 = _mm_load_si128(output + 7);
-    xout4 = _mm_load_si128(output + 8);
-    xout5 = _mm_load_si128(output + 9);
-    xout6 = _mm_load_si128(output + 10);
-    xout7 = _mm_load_si128(output + 11);
-
-    for (size_t i = 0; __builtin_expect(i < MEMORY / sizeof(__m128i), 1); i += 8)
-    {
-        xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0);
-        xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1);
-        xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2);
-        xout3 = _mm_xor_si128(_mm_load_si128(input + i + 3), xout3);
-        xout4 = _mm_xor_si128(_mm_load_si128(input + i + 4), xout4);
-        xout5 = _mm_xor_si128(_mm_load_si128(input + i + 5), xout5);
-        xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6);
-        xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7);
-
-        aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-    }
-
-    _mm_store_si128(output + 4, xout0);
-    _mm_store_si128(output + 5, xout1);
-    _mm_store_si128(output + 6, xout2);
-    _mm_store_si128(output + 7, xout3);
-    _mm_store_si128(output + 8, xout4);
-    _mm_store_si128(output + 9, xout5);
-    _mm_store_si128(output + 10, xout6);
-    _mm_store_si128(output + 11, xout7);
-}
-
-
-#if defined(__x86_64__)
-#   define EXTRACT64(X) _mm_cvtsi128_si64(X)
-
-inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi)
-{
-    unsigned __int128 r = (unsigned __int128) a * (unsigned __int128) b;
-    *hi = r >> 64;
-    return (uint64_t) r;
-}
-#elif defined(__i386__)
-#   define HI32(X) \
-    _mm_srli_si128((X), 4)
-
-
-#   define EXTRACT64(X) \
-    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \
-    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32))
-
-inline uint64_t _umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) {
-    // multiplier   = ab = a * 2^32 + b
-    // multiplicand = cd = c * 2^32 + d
-    // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
-    uint64_t a = multiplier >> 32;
-    uint64_t b = multiplier & 0xFFFFFFFF;
-    uint64_t c = multiplicand >> 32;
-    uint64_t d = multiplicand & 0xFFFFFFFF;
-
-    //uint64_t ac = a * c;
-    uint64_t ad = a * d;
-    //uint64_t bc = b * c;
-    uint64_t bd = b * d;
-
-    uint64_t adbc = ad + (b * c);
-    uint64_t adbc_carry = adbc < ad ? 1 : 0;
-
-    // multiplier * multiplicand = product_hi * 2^64 + product_lo
-    uint64_t product_lo = bd + (adbc << 32);
-    uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
-    *product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
-
-    return product_lo;
-}
-#endif
-
-
-#endif /* __CRYPTONIGHT_AESNI_H__ */
diff --git a/algo/cryptonight/cryptonight_av1_aesni.c b/algo/cryptonight/cryptonight_av1_aesni.c
deleted file mode 100644
index 3f30544e6..000000000
--- a/algo/cryptonight/cryptonight_av1_aesni.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <x86intrin.h>
-#include <string.h>
-
-#include "cryptonight.h"
-#include "cryptonight_aesni.h"
-#include "crypto/c_keccak.h"
-
-
-void cryptonight_av1_aesni(const void *restrict input, size_t size, void *restrict output, struct cryptonight_ctx *restrict ctx)
-{
-    keccak((const uint8_t *) input, size, ctx->state0, 200);
-
-    cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory);
-
-    const uint8_t* l0 = ctx->memory;
-    uint64_t* h0 = (uint64_t*) ctx->state0;
-
-    uint64_t al0 = h0[0] ^ h0[4];
-    uint64_t ah0 = h0[1] ^ h0[5];
-    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
-
-    uint64_t idx0 = h0[0] ^ h0[4];
-
-    for (size_t i = 0; __builtin_expect(i < 0x80000, 1); i++) {
-        __m128i cx;
-        cx = _mm_load_si128((__m128i *) &l0[idx0 & 0x1FFFF0]);
-        cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0));
-
-        _mm_store_si128((__m128i *) &l0[idx0 & 0x1FFFF0], _mm_xor_si128(bx0, cx));
-        idx0 = EXTRACT64(cx);
-        bx0 = cx;
-
-        uint64_t hi, lo, cl, ch;
-        cl = ((uint64_t*) &l0[idx0 & 0x1FFFF0])[0];
-        ch = ((uint64_t*) &l0[idx0 & 0x1FFFF0])[1];
-        lo = _umul128(idx0, cl, &hi);
-
-        al0 += hi;
-        ah0 += lo;
-
-        ((uint64_t*)&l0[idx0 & 0x1FFFF0])[0] = al0;
-        ((uint64_t*)&l0[idx0 & 0x1FFFF0])[1] = ah0;
-
-        ah0 ^= ch;
-        al0 ^= cl;
-        idx0 = al0;
-    }
-
-    cn_implode_scratchpad((__m128i*) ctx->memory, (__m128i*) ctx->state0);
-
-    keccakf(h0, 24);
-    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output);
-}
diff --git a/algo/cryptonight/cryptonight_av2_aesni_double.c b/algo/cryptonight/cryptonight_av2_aesni_double.c
deleted file mode 100644
index 779b9bc3f..000000000
--- a/algo/cryptonight/cryptonight_av2_aesni_double.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <x86intrin.h>
-#include <string.h>
-
-#include "cryptonight.h"
-#include "cryptonight_aesni.h"
-#include "crypto/c_keccak.h"
-
-
-void cryptonight_av2_aesni_double(const void *restrict input, size_t size, void *restrict output, struct cryptonight_ctx *restrict ctx)
-{
-    keccak((const uint8_t *) input,        size, ctx->state0, 200);
-    keccak((const uint8_t *) input + size, size, ctx->state1, 200);
-
-    const uint8_t* l0 = ctx->memory;
-    const uint8_t* l1 = ctx->memory + MEMORY;
-    uint64_t* h0 = (uint64_t*) ctx->state0;
-    uint64_t* h1 = (uint64_t*) ctx->state1;
-
-    cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
-    cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
-
-    uint64_t al0 = h0[0] ^ h0[4];
-    uint64_t al1 = h1[0] ^ h1[4];
-    uint64_t ah0 = h0[1] ^ h0[5];
-    uint64_t ah1 = h1[1] ^ h1[5];
-
-    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
-    __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
-
-    uint64_t idx0 = h0[0] ^ h0[4];
-    uint64_t idx1 = h1[0] ^ h1[4];
-
-    for (size_t i = 0; __builtin_expect(i < 0x80000, 1); i++) {
-        __m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & 0x1FFFF0]);
-        __m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & 0x1FFFF0]);
-
-        cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0));
-        cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1));
-
-        _mm_store_si128((__m128i *) &l0[idx0 & 0x1FFFF0], _mm_xor_si128(bx0, cx0));
-        _mm_store_si128((__m128i *) &l1[idx1 & 0x1FFFF0], _mm_xor_si128(bx1, cx1));
-
-        idx0 = EXTRACT64(cx0);
-        idx1 = EXTRACT64(cx1);
-
-        bx0 = cx0;
-        bx1 = cx1;
-
-        uint64_t hi, lo, cl, ch;
-        cl = ((uint64_t*) &l0[idx0 & 0x1FFFF0])[0];
-        ch = ((uint64_t*) &l0[idx0 & 0x1FFFF0])[1];
-        lo = _umul128(idx0, cl, &hi);
-
-        al0 += hi;
-        ah0 += lo;
-
-        ((uint64_t*) &l0[idx0 & 0x1FFFF0])[0] = al0;
-        ((uint64_t*) &l0[idx0 & 0x1FFFF0])[1] = ah0;
-
-        ah0 ^= ch;
-        al0 ^= cl;
-        idx0 = al0;
-
-        cl = ((uint64_t*) &l1[idx1 & 0x1FFFF0])[0];
-        ch = ((uint64_t*) &l1[idx1 & 0x1FFFF0])[1];
-        lo = _umul128(idx1, cl, &hi);
-
-        al1 += hi;
-        ah1 += lo;
-
-        ((uint64_t*) &l1[idx1 & 0x1FFFF0])[0] = al1;
-        ((uint64_t*) &l1[idx1 & 0x1FFFF0])[1] = ah1;
-
-        ah1 ^= ch;
-        al1 ^= cl;
-        idx1 = al1;
-    }
-
-    cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
-    cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
-
-    keccakf(h0, 24);
-    keccakf(h1, 24);
-
-    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output);
-    extra_hashes[ctx->state1[0] & 3](ctx->state1, 200, (char*) output + 32);
-}
diff --git a/algo/cryptonight/cryptonight_av3_softaes.c b/algo/cryptonight/cryptonight_av3_softaes.c
deleted file mode 100644
index 22be894d8..000000000
--- a/algo/cryptonight/cryptonight_av3_softaes.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <x86intrin.h>
-#include <string.h>
-
-#include "cryptonight.h"
-#include "cryptonight_softaes.h"
-#include "crypto/c_keccak.h"
-
-
-void cryptonight_av3_softaes(const void *restrict input, size_t size, void *restrict output, struct cryptonight_ctx *restrict ctx)
-{
-    keccak((const uint8_t *) input, size, ctx->state0, 200);
-
-    cn_explode_scratchpad((__m128i*) ctx->state0, (__m128i*) ctx->memory);
-
-    const uint8_t* l0 = ctx->memory;
-    uint64_t* h0 = (uint64_t*) ctx->state0;
-
-    uint64_t al0 = h0[0] ^ h0[4];
-    uint64_t ah0 = h0[1] ^ h0[5];
-    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
-
-    uint64_t idx0 = h0[0] ^ h0[4];
-
-    for (size_t i = 0; __builtin_expect(i < 0x80000, 1); i++) {
-        __m128i cx;
-        cx = _mm_load_si128((__m128i *)&l0[idx0 & 0x1FFFF0]);
-        cx = soft_aesenc(cx, _mm_set_epi64x(ah0, al0));
-
-        _mm_store_si128((__m128i *)&l0[idx0 & 0x1FFFF0], _mm_xor_si128(bx0, cx));
-        idx0 = EXTRACT64(cx);
-        bx0 = cx;
-
-        uint64_t hi, lo, cl, ch;
-        cl = ((uint64_t*)&l0[idx0 & 0x1FFFF0])[0];
-        ch = ((uint64_t*)&l0[idx0 & 0x1FFFF0])[1];
-        lo = _umul128(idx0, cl, &hi);
-
-        al0 += hi;
-        ah0 += lo;
-
-        ((uint64_t*)&l0[idx0 & 0x1FFFF0])[0] = al0;
-        ((uint64_t*)&l0[idx0 & 0x1FFFF0])[1] = ah0;
-
-        ah0 ^= ch;
-        al0 ^= cl;
-        idx0 = al0;
-    }
-
-    cn_implode_scratchpad((__m128i*) ctx->memory, (__m128i*) ctx->state0);
-
-    keccakf(h0, 24);
-    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output);
-}
diff --git a/algo/cryptonight/cryptonight_av4_softaes_double.c b/algo/cryptonight/cryptonight_av4_softaes_double.c
deleted file mode 100644
index afd4bebe1..000000000
--- a/algo/cryptonight/cryptonight_av4_softaes_double.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <x86intrin.h>
-#include <string.h>
-
-#include "cryptonight.h"
-#include "cryptonight_softaes.h"
-#include "crypto/c_keccak.h"
-
-
-void cryptonight_av4_softaes_double(const void *restrict input, size_t size, void *restrict output, struct cryptonight_ctx *restrict ctx)
-{
-    keccak((const uint8_t *) input,        size, ctx->state0, 200);
-    keccak((const uint8_t *) input + size, size, ctx->state1, 200);
-
-    const uint8_t* l0 = ctx->memory;
-    const uint8_t* l1 = ctx->memory + MEMORY;
-    uint64_t* h0 = (uint64_t*) ctx->state0;
-    uint64_t* h1 = (uint64_t*) ctx->state1;
-
-    cn_explode_scratchpad((__m128i*) h0, (__m128i*) l0);
-    cn_explode_scratchpad((__m128i*) h1, (__m128i*) l1);
-
-    uint64_t al0 = h0[0] ^ h0[4];
-    uint64_t al1 = h1[0] ^ h1[4];
-    uint64_t ah0 = h0[1] ^ h0[5];
-    uint64_t ah1 = h1[1] ^ h1[5];
-
-    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
-    __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
-
-    uint64_t idx0 = h0[0] ^ h0[4];
-    uint64_t idx1 = h1[0] ^ h1[4];
-
-    for (size_t i = 0; __builtin_expect(i < 0x80000, 1); i++) {
-        __m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & 0x1FFFF0]);
-        __m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & 0x1FFFF0]);
-
-        cx0 = soft_aesenc(cx0, _mm_set_epi64x(ah0, al0));
-        cx1 = soft_aesenc(cx1, _mm_set_epi64x(ah1, al1));
-
-        _mm_store_si128((__m128i *) &l0[idx0 & 0x1FFFF0], _mm_xor_si128(bx0, cx0));
-        _mm_store_si128((__m128i *) &l1[idx1 & 0x1FFFF0], _mm_xor_si128(bx1, cx1));
-
-        idx0 = EXTRACT64(cx0);
-        idx1 = EXTRACT64(cx1);
-
-        bx0 = cx0;
-        bx1 = cx1;
-
-        uint64_t hi, lo, cl, ch;
-        cl = ((uint64_t*) &l0[idx0 & 0x1FFFF0])[0];
-        ch = ((uint64_t*) &l0[idx0 & 0x1FFFF0])[1];
-        lo = _umul128(idx0, cl, &hi);
-
-        al0 += hi;
-        ah0 += lo;
-
-        ((uint64_t*) &l0[idx0 & 0x1FFFF0])[0] = al0;
-        ((uint64_t*) &l0[idx0 & 0x1FFFF0])[1] = ah0;
-
-        ah0 ^= ch;
-        al0 ^= cl;
-        idx0 = al0;
-
-        cl = ((uint64_t*) &l1[idx1 & 0x1FFFF0])[0];
-        ch = ((uint64_t*) &l1[idx1 & 0x1FFFF0])[1];
-        lo = _umul128(idx1, cl, &hi);
-
-        al1 += hi;
-        ah1 += lo;
-
-        ((uint64_t*) &l1[idx1 & 0x1FFFF0])[0] = al1;
-        ((uint64_t*) &l1[idx1 & 0x1FFFF0])[1] = ah1;
-
-        ah1 ^= ch;
-        al1 ^= cl;
-        idx1 = al1;
-    }
-
-    cn_implode_scratchpad((__m128i*) l0, (__m128i*) h0);
-    cn_implode_scratchpad((__m128i*) l1, (__m128i*) h1);
-
-    keccakf(h0, 24);
-    keccakf(h1, 24);
-
-    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, output);
-    extra_hashes[ctx->state1[0] & 3](ctx->state1, 200, (char*) output + 32);
-}
diff --git a/algo/cryptonight/cryptonight_softaes.h b/algo/cryptonight/cryptonight_softaes.h
deleted file mode 100644
index 1948db05f..000000000
--- a/algo/cryptonight/cryptonight_softaes.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017      fireice-uk  <https://github.com/fireice-uk>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __CRYPTONIGHT_SOFTAES_H__
-#define __CRYPTONIGHT_SOFTAES_H__
-
-#include <x86intrin.h>
-
-extern __m128i soft_aesenc(__m128i in, __m128i key);
-extern __m128i soft_aeskeygenassist(__m128i key, uint8_t rcon);
-
-
-// This will shift and xor tmp1 into itself as 4 32-bit vals such as
-// sl_xor(a1 a2 a3 a4) = a1 (a2^a1) (a3^a2^a1) (a4^a3^a2^a1)
-inline __m128i sl_xor(__m128i tmp1)
-{
-    __m128i tmp4;
-    tmp4 = _mm_slli_si128(tmp1, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    tmp4 = _mm_slli_si128(tmp4, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    tmp4 = _mm_slli_si128(tmp4, 0x04);
-    tmp1 = _mm_xor_si128(tmp1, tmp4);
-    return tmp1;
-}
-
-
-inline void aes_genkey_sub(__m128i* xout0, __m128i* xout2, uint8_t rcon)
-{
-    __m128i xout1 = soft_aeskeygenassist(*xout2, rcon);
-    xout1  = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
-    *xout0 = sl_xor(*xout0);
-    *xout0 = _mm_xor_si128(*xout0, xout1);
-    xout1  = soft_aeskeygenassist(*xout0, 0x00);
-    xout1  = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
-    *xout2 = sl_xor(*xout2);
-    *xout2 = _mm_xor_si128(*xout2, xout1);
-}
-
-
-inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
-{
-    *x0 = soft_aesenc(*x0, key);
-    *x1 = soft_aesenc(*x1, key);
-    *x2 = soft_aesenc(*x2, key);
-    *x3 = soft_aesenc(*x3, key);
-    *x4 = soft_aesenc(*x4, key);
-    *x5 = soft_aesenc(*x5, key);
-    *x6 = soft_aesenc(*x6, key);
-    *x7 = soft_aesenc(*x7, key);
-}
-
-
-inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3, __m128i* k4, __m128i* k5, __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
-{
-    __m128i xout0 = _mm_load_si128(memory);
-    __m128i xout2 = _mm_load_si128(memory + 1);
-    *k0 = xout0;
-    *k1 = xout2;
-
-    aes_genkey_sub(&xout0, &xout2, 0x1);
-    *k2 = xout0;
-    *k3 = xout2;
-
-    aes_genkey_sub(&xout0, &xout2, 0x2);
-    *k4 = xout0;
-    *k5 = xout2;
-
-    aes_genkey_sub(&xout0, &xout2, 0x4);
-    *k6 = xout0;
-    *k7 = xout2;
-
-    aes_genkey_sub(&xout0, &xout2, 0x8);
-    *k8 = xout0;
-    *k9 = xout2;
-}
-
-
-inline void cn_explode_scratchpad(const __m128i* input, __m128i* output)
-{
-    // This is more than we have registers, compiler will assign 2 keys on the stack
-    __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7;
-    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
-
-    aes_genkey(input, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
-
-    xin0 = _mm_load_si128(input + 4);
-    xin1 = _mm_load_si128(input + 5);
-    xin2 = _mm_load_si128(input + 6);
-    xin3 = _mm_load_si128(input + 7);
-    xin4 = _mm_load_si128(input + 8);
-    xin5 = _mm_load_si128(input + 9);
-    xin6 = _mm_load_si128(input + 10);
-    xin7 = _mm_load_si128(input + 11);
-
-    for (size_t i = 0; i < MEMORY / sizeof(__m128i); i += 8) {
-        aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-        aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
-
-        _mm_store_si128(output + i + 0, xin0);
-        _mm_store_si128(output + i + 1, xin1);
-        _mm_store_si128(output + i + 2, xin2);
-        _mm_store_si128(output + i + 3, xin3);
-        _mm_store_si128(output + i + 4, xin4);
-        _mm_store_si128(output + i + 5, xin5);
-        _mm_store_si128(output + i + 6, xin6);
-        _mm_store_si128(output + i + 7, xin7);
-    }
-}
-
-
-inline void cn_implode_scratchpad(const __m128i* input, __m128i* output)
-{
-    // This is more than we have registers, compiler will assign 2 keys on the stack
-    __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7;
-    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
-
-    aes_genkey(output + 2, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
-
-    xout0 = _mm_load_si128(output + 4);
-    xout1 = _mm_load_si128(output + 5);
-    xout2 = _mm_load_si128(output + 6);
-    xout3 = _mm_load_si128(output + 7);
-    xout4 = _mm_load_si128(output + 8);
-    xout5 = _mm_load_si128(output + 9);
-    xout6 = _mm_load_si128(output + 10);
-    xout7 = _mm_load_si128(output + 11);
-
-    for (size_t i = 0; __builtin_expect(i < MEMORY / sizeof(__m128i), 1); i += 8)
-    {
-        xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0);
-        xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1);
-        xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2);
-        xout3 = _mm_xor_si128(_mm_load_si128(input + i + 3), xout3);
-        xout4 = _mm_xor_si128(_mm_load_si128(input + i + 4), xout4);
-        xout5 = _mm_xor_si128(_mm_load_si128(input + i + 5), xout5);
-        xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6);
-        xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7);
-
-        aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-        aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
-    }
-
-    _mm_store_si128(output + 4, xout0);
-    _mm_store_si128(output + 5, xout1);
-    _mm_store_si128(output + 6, xout2);
-    _mm_store_si128(output + 7, xout3);
-    _mm_store_si128(output + 8, xout4);
-    _mm_store_si128(output + 9, xout5);
-    _mm_store_si128(output + 10, xout6);
-    _mm_store_si128(output + 11, xout7);
-}
-
-
-#if defined(__x86_64__)
-#   define EXTRACT64(X) _mm_cvtsi128_si64(X)
-
-inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi)
-{
-    unsigned __int128 r = (unsigned __int128) a * (unsigned __int128) b;
-    *hi = r >> 64;
-    return (uint64_t) r;
-}
-#elif defined(__i386__)
-#   define HI32(X) \
-    _mm_srli_si128((X), 4)
-
-
-#   define EXTRACT64(X) \
-    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \
-    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32))
-
-inline uint64_t _umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) {
-    // multiplier   = ab = a * 2^32 + b
-    // multiplicand = cd = c * 2^32 + d
-    // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
-    uint64_t a = multiplier >> 32;
-    uint64_t b = multiplier & 0xFFFFFFFF;
-    uint64_t c = multiplicand >> 32;
-    uint64_t d = multiplicand & 0xFFFFFFFF;
-
-    //uint64_t ac = a * c;
-    uint64_t ad = a * d;
-    //uint64_t bc = b * c;
-    uint64_t bd = b * d;
-
-    uint64_t adbc = ad + (b * c);
-    uint64_t adbc_carry = adbc < ad ? 1 : 0;
-
-    // multiplier * multiplicand = product_hi * 2^64 + product_lo
-    uint64_t product_lo = bd + (adbc << 32);
-    uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
-    *product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
-
-    return product_lo;
-}
-#endif
-
-
-#endif /* __CRYPTONIGHT_SOFTAES_H__ */
diff --git a/cmake/FindUV.cmake b/cmake/FindUV.cmake
new file mode 100644
index 000000000..e3c22d28d
--- /dev/null
+++ b/cmake/FindUV.cmake
@@ -0,0 +1,8 @@
+find_path(UV_INCLUDE_DIR NAMES uv.h)
+find_library(UV_LIBRARY NAMES uv libuv)
+
+set(UV_LIBRARIES ${UV_LIBRARY})
+set(UV_INCLUDE_DIRS ${UV_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(UV DEFAULT_MSG UV_LIBRARY UV_INCLUDE_DIR)
diff --git a/compat/libcpuid/libcpuid_util.c b/compat/libcpuid/libcpuid_util.c
deleted file mode 100644
index 4de1871a4..000000000
--- a/compat/libcpuid/libcpuid_util.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright 2008  Veselin Georgiev,
- * anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
-#include "libcpuid.h"
-#include "libcpuid_util.h"
-
-int _current_verboselevel;
-
-void match_features(const struct feature_map_t* matchtable, int count, uint32_t reg, struct cpu_id_t* data)
-{
-	int i;
-	for (i = 0; i < count; i++)
-		if (reg & (1u << matchtable[i].bit))
-			data->flags[matchtable[i].feature] = 1;
-}
-
-static void default_warn(const char *msg)
-{
-	fprintf(stderr, "%s", msg);
-}
-
-libcpuid_warn_fn_t _warn_fun = default_warn;
-
-#if defined(_MSC_VER)
-#	define vsnprintf _vsnprintf
-#endif
-void warnf(const char* format, ...)
-{
-	char buff[1024];
-	va_list va;
-	if (!_warn_fun) return;
-	va_start(va, format);
-	vsnprintf(buff, sizeof(buff), format, va);
-	va_end(va);
-	_warn_fun(buff);
-}
-
-void debugf(int verboselevel, const char* format, ...)
-{
-	char buff[1024];
-	va_list va;
-	if (verboselevel > _current_verboselevel) return;
-	va_start(va, format);
-	vsnprintf(buff, sizeof(buff), format, va);
-	va_end(va);
-	_warn_fun(buff);
-}
-
-static int popcount64(uint64_t mask)
-{
-	int num_set_bits = 0;
-	
-	while (mask) {
-		mask &= mask - 1;
-		num_set_bits++;
-	}
-	
-	return num_set_bits;
-}
-
-static int score(const struct match_entry_t* entry, const struct cpu_id_t* data,
-                 int brand_code, uint64_t bits, int model_code)
-{
-	int res = 0;
-	if (entry->family	== data->family    ) res += 2;
-	if (entry->model	== data->model     ) res += 2;
-	if (entry->stepping	== data->stepping  ) res += 2;
-	if (entry->ext_family	== data->ext_family) res += 2;
-	if (entry->ext_model	== data->ext_model ) res += 2;
-	if (entry->ncores	== data->num_cores ) res += 2;
-	if (entry->l2cache	== data->l2_cache  ) res += 1;
-	if (entry->l3cache	== data->l3_cache  ) res += 1;
-	if (entry->brand_code   == brand_code  ) res += 2;
-	if (entry->model_code   == model_code  ) res += 2;
-	
-	res += popcount64(entry->model_bits & bits) * 2;
-	return res;
-}
-
-int match_cpu_codename(const struct match_entry_t* matchtable, int count,
-                       struct cpu_id_t* data, int brand_code, uint64_t bits,
-                       int model_code)
-{
-	int bestscore = -1;
-	int bestindex = 0;
-	int i, t;
-	
-	debugf(3, "Matching cpu f:%d, m:%d, s:%d, xf:%d, xm:%d, ncore:%d, l2:%d, bcode:%d, bits:%llu, code:%d\n",
-		data->family, data->model, data->stepping, data->ext_family,
-		data->ext_model, data->num_cores, data->l2_cache, brand_code, (unsigned long long) bits, model_code);
-	
-	for (i = 0; i < count; i++) {
-		t = score(&matchtable[i], data, brand_code, bits, model_code);
-		debugf(3, "Entry %d, `%s', score %d\n", i, matchtable[i].name, t);
-		if (t > bestscore) {
-			debugf(2, "Entry `%s' selected - best score so far (%d)\n", matchtable[i].name, t);
-			bestscore = t;
-			bestindex = i;
-		}
-	}
-	strcpy(data->cpu_codename, matchtable[bestindex].name);
-	return bestscore;
-}
-
-void generic_get_cpu_list(const struct match_entry_t* matchtable, int count,
-                          struct cpu_list_t* list)
-{
-	int i, j, n, good;
-	n = 0;
-	list->names = (char**) malloc(sizeof(char*) * count);
-	for (i = 0; i < count; i++) {
-		if (strstr(matchtable[i].name, "Unknown")) continue;
-		good = 1;
-		for (j = n - 1; j >= 0; j--)
-			if (!strcmp(list->names[j], matchtable[i].name)) {
-				good = 0;
-				break;
-			}
-		if (!good) continue;
-#if defined(_MSC_VER)
-		list->names[n++] = _strdup(matchtable[i].name);
-#else
-		list->names[n++] = strdup(matchtable[i].name);
-#endif
-	}
-	list->num_entries = n;
-}
-
-static int xmatch_entry(char c, const char* p)
-{
-	int i, j;
-	if (c == 0) return -1;
-	if (c == p[0]) return 1;
-	if (p[0] == '.') return 1;
-	if (p[0] == '#' && isdigit(c)) return 1;
-	if (p[0] == '[') {
-		j = 1;
-		while (p[j] && p[j] != ']') j++;
-		if (!p[j]) return -1;
-		for (i = 1; i < j; i++)
-			if (p[i] == c) return j + 1;
-	}
-	return -1;
-}
-
-int match_pattern(const char* s, const char* p)
-{
-	int i, j, dj, k, n, m;
-	n = (int) strlen(s);
-	m = (int) strlen(p);
-	for (i = 0; i < n; i++) {
-		if (xmatch_entry(s[i], p) != -1) {
-			j = 0;
-			k = 0;
-			while (j < m && ((dj = xmatch_entry(s[i + k], p + j)) != -1)) {
-				k++;
-				j += dj;
-			}
-			if (j == m) return i + 1;
-		}
-	}
-	return 0;
-}
-
-struct cpu_id_t* get_cached_cpuid(void)
-{
-	static int initialized = 0;
-	static struct cpu_id_t id;
-	if (initialized) return &id;
-	if (cpu_identify(NULL, &id))
-		memset(&id, 0, sizeof(id));
-	initialized = 1;
-	return &id;
-}
-
-int match_all(uint64_t bits, uint64_t mask)
-{
-	return (bits & mask) == mask;
-}
-
-void debug_print_lbits(int debuglevel, uint64_t mask)
-{
-	int i, first = 0;
-	for (i = 0; i < 64; i++) if (mask & (((uint64_t) 1) << i)) {
-		if (first) first = 0;
-		else debugf(2, " + ");
-		debugf(2, "LBIT(%d)", i);
-	}
-	debugf(2, "\n");
-}
diff --git a/compat/libcpuid/recog_amd.c b/compat/libcpuid/recog_amd.c
deleted file mode 100644
index b735c4005..000000000
--- a/compat/libcpuid/recog_amd.c
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * Copyright 2008  Veselin Georgiev,
- * anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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>
-#include <string.h>
-#include <ctype.h>
-#include "libcpuid.h"
-#include "libcpuid_util.h"
-#include "libcpuid_internal.h"
-#include "recog_amd.h"
-
-const struct amd_code_str { amd_code_t code; char *str; } amd_code_str[] = {
-	#define CODE(x) { x, #x }
-	#define CODE2(x, y) CODE(x)
-	#include "amd_code_t.h"
-	#undef CODE
-};
-
-struct amd_code_and_bits_t {
-	int code;
-	uint64_t bits;
-};
-
-enum _amd_bits_t {
-	ATHLON_      = LBIT(  0 ),
-	_XP_         = LBIT(  1 ),
-	_M_          = LBIT(  2 ),
-	_MP_         = LBIT(  3 ),
-	MOBILE_      = LBIT(  4 ),
-	DURON_       = LBIT(  5 ),
-	SEMPRON_     = LBIT(  6 ),
-	OPTERON_     = LBIT(  7 ),
-	TURION_      = LBIT(  8 ),
-	_LV_         = LBIT(  9 ),
-	_64_         = LBIT( 10 ),
-	_X2          = LBIT( 11 ),
-	_X3          = LBIT( 12 ),
-	_X4          = LBIT( 13 ),
-	_X6          = LBIT( 14 ),
-	_FX          = LBIT( 15 ),
-};
-typedef enum _amd_bits_t amd_bits_t;
-
-enum _amd_model_codes_t {
-	// Only for Ryzen CPUs:
-	_1400,
-	_1500,
-	_1600,
-};
-
-
-const struct match_entry_t cpudb_amd[] = {
-	{ -1, -1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown AMD CPU"               },
-	
-	/* 486 and the likes */
-	{  4, -1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown AMD 486"               },
-	{  4,  3, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "AMD 486DX2"                    },
-	{  4,  7, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "AMD 486DX2WB"                  },
-	{  4,  8, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "AMD 486DX4"                    },
-	{  4,  9, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "AMD 486DX4WB"                  },
-	
-	/* Pentia clones */
-	{  5, -1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown AMD 586"               },
-	{  5,  0, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K5"                            },
-	{  5,  1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K5"                            },
-	{  5,  2, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K5"                            },
-	{  5,  3, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K5"                            },
-	
-	/* The K6 */
-	{  5,  6, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6"                            },
-	{  5,  7, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6"                            },
-	
-	{  5,  8, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6-2"                          },
-	{  5,  9, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6-III"                        },
-	{  5, 10, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K6"                    },
-	{  5, 11, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K6"                    },
-	{  5, 12, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K6"                    },
-	{  5, 13, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "K6-2+"                         },
-	
-	/* Athlon et al. */
-	{  6,  1, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon (Slot-A)"               },
-	{  6,  2, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon (Slot-A)"               },
-	{  6,  3, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Duron (Spitfire)"              },
-	{  6,  4, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon (ThunderBird)"          },
-	
-	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown Athlon"                },
-	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_             ,     0, "Athlon (Palomino)"             },
-	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_MP_        ,     0, "Athlon MP (Palomino)"          },
-	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, DURON_              ,     0, "Duron (Palomino)"              },
-	{  6,  6, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_        ,     0, "Athlon XP"                     },
-	
-	{  6,  7, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown Athlon XP"             },
-	{  6,  7, -1, -1,   -1,   1,    -1,    -1, NC, DURON_              ,     0, "Duron (Morgan)"                },
-	
-	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon XP"                     },
-	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_             ,     0, "Athlon XP (Thoroughbred)"      },
-	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_        ,     0, "Athlon XP (Thoroughbred)"      },
-	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, DURON_              ,     0, "Duron (Applebred)"             },
-	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, SEMPRON_            ,     0, "Sempron (Thoroughbred)"        },
-	{  6,  8, -1, -1,   -1,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron (Thoroughbred)"        },
-	{  6,  8, -1, -1,   -1,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron (Thoroughbred)"        },
-	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_MP_        ,     0, "Athlon MP (Thoroughbred)"      },
-	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_|_M_    ,     0, "Mobile Athlon (T-Bred)"        },
-	{  6,  8, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_|_M_|_LV_,    0, "Mobile Athlon (T-Bred)"        },
-	
-	{  6, 10, -1, -1,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Athlon XP (Barton)"            },
-	{  6, 10, -1, -1,   -1,   1,   512,    -1, NC, ATHLON_|_XP_        ,     0, "Athlon XP (Barton)"            },
-	{  6, 10, -1, -1,   -1,   1,   512,    -1, NC, SEMPRON_            ,     0, "Sempron (Barton)"              },
-	{  6, 10, -1, -1,   -1,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron (Thorton)"             },
-	{  6, 10, -1, -1,   -1,   1,   256,    -1, NC, ATHLON_|_XP_        ,     0, "Athlon XP (Thorton)"           },
-	{  6, 10, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_MP_        ,     0, "Athlon MP (Barton)"            },
-	{  6, 10, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_|_M_    ,     0, "Mobile Athlon (Barton)"        },
-	{  6, 10, -1, -1,   -1,   1,    -1,    -1, NC, ATHLON_|_XP_|_M_|_LV_,    0, "Mobile Athlon (Barton)"        },
-	
-	/* K8 Architecture */
-	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K8"                    },
-	{ 15, -1, -1, 16,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown K9"                    },
-	
-	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, 0                   ,     0, "Unknown A64"                   },
-	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, OPTERON_            ,     0, "Opteron"                       },
-	{ 15, -1, -1, 15,   -1,   2,    -1,    -1, NC, OPTERON_|_X2        ,     0, "Opteron (Dual Core)"           },
-	{ 15,  3, -1, 15,   -1,   1,    -1,    -1, NC, OPTERON_            ,     0, "Opteron"                       },
-	{ 15,  3, -1, 15,   -1,   2,    -1,    -1, NC, OPTERON_|_X2        ,     0, "Opteron (Dual Core)"           },
-	{ 15, -1, -1, 15,   -1,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (512K)"              },
-	{ 15, -1, -1, 15,   -1,   1,  1024,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (1024K)"             },
-	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, ATHLON_|_FX         ,     0, "Athlon FX"                     },
-	{ 15, -1, -1, 15,   -1,   1,    -1,    -1, NC, ATHLON_|_64_|_FX    ,     0, "Athlon 64 FX"                  },
-	{ 15,  3, -1, 15,   35,   2,    -1,    -1, NC, ATHLON_|_64_|_FX    ,     0, "Athlon 64 FX X2 (Toledo)"      },
-	{ 15, -1, -1, 15,   -1,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (512K)"           },
-	{ 15, -1, -1, 15,   -1,   2,  1024,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (1024K)"          },
-	{ 15, -1, -1, 15,   -1,   1,   512,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (512K)"              },
-	{ 15, -1, -1, 15,   -1,   1,  1024,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (1024K)"             },
-	{ 15, -1, -1, 15,   -1,   2,   512,    -1, NC, TURION_|_X2         ,     0, "Turion 64 X2 (512K)"           },
-	{ 15, -1, -1, 15,   -1,   2,  1024,    -1, NC, TURION_|_X2         ,     0, "Turion 64 X2 (1024K)"          },
-	{ 15, -1, -1, 15,   -1,   1,   128,    -1, NC, SEMPRON_            ,     0, "A64 Sempron (128K)"            },
-	{ 15, -1, -1, 15,   -1,   1,   256,    -1, NC, SEMPRON_            ,     0, "A64 Sempron (256K)"            },
-	{ 15, -1, -1, 15,   -1,   1,   512,    -1, NC, SEMPRON_            ,     0, "A64 Sempron (512K)"            },
-	{ 15, -1, -1, 15, 0x4f,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Orleans/512K)"      },
-	{ 15, -1, -1, 15, 0x5f,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Orleans/512K)"      },
-	{ 15, -1, -1, 15, 0x2f,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Venice/512K)"       },
-	{ 15, -1, -1, 15, 0x2c,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Venice/512K)"       },
-	{ 15, -1, -1, 15, 0x1f,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Winchester/512K)"   },
-	{ 15, -1, -1, 15, 0x0c,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Newcastle/512K)"    },
-	{ 15, -1, -1, 15, 0x27,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (San Diego/512K)"    },
-	{ 15, -1, -1, 15, 0x37,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (San Diego/512K)"    },
-	{ 15, -1, -1, 15, 0x04,   1,   512,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (ClawHammer/512K)"   },
-	
-	{ 15, -1, -1, 15, 0x5f,   1,  1024,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (Orleans/1024K)"     },
-	{ 15, -1, -1, 15, 0x27,   1,  1024,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (San Diego/1024K)"   },
-	{ 15, -1, -1, 15, 0x04,   1,  1024,    -1, NC, ATHLON_|_64_        ,     0, "Athlon 64 (ClawHammer/1024K)"  },
-	
-	{ 15, -1, -1, 15, 0x4b,   2,   256,    -1, NC, SEMPRON_            ,     0, "Athlon 64 X2 (Windsor/256K)"   },
-	
-	{ 15, -1, -1, 15, 0x23,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Toledo/512K)"    },
-	{ 15, -1, -1, 15, 0x4b,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Windsor/512K)"   },
-	{ 15, -1, -1, 15, 0x43,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Windsor/512K)"   },
-	{ 15, -1, -1, 15, 0x6b,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Brisbane/512K)"  },
-	{ 15, -1, -1, 15, 0x2b,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Manchester/512K)"},
-	
-	{ 15, -1, -1, 15, 0x23,   2,  1024,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Toledo/1024K)"   },
-	{ 15, -1, -1, 15, 0x43,   2,  1024,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon 64 X2 (Windsor/1024K)"  },
-	
-	{ 15, -1, -1, 15, 0x08,   1,   128,    -1, NC, MOBILE_|SEMPRON_    ,     0, "Mobile Sempron 64 (Dublin/128K)"},
-	{ 15, -1, -1, 15, 0x08,   1,   256,    -1, NC, MOBILE_|SEMPRON_    ,     0, "Mobile Sempron 64 (Dublin/256K)"},
-	{ 15, -1, -1, 15, 0x0c,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Paris)"            },
-	{ 15, -1, -1, 15, 0x1c,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/128K)"     },
-	{ 15, -1, -1, 15, 0x1c,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/256K)"     },
-	{ 15, -1, -1, 15, 0x1c,   1,   128,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Sonora/128K)"},
-	{ 15, -1, -1, 15, 0x1c,   1,   256,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Sonora/256K)"},
-	{ 15, -1, -1, 15, 0x2c,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/128K)"     },
-	{ 15, -1, -1, 15, 0x2c,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/256K)"     },
-	{ 15, -1, -1, 15, 0x2c,   1,   128,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Albany/128K)"},
-	{ 15, -1, -1, 15, 0x2c,   1,   256,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Albany/256K)"},
-	{ 15, -1, -1, 15, 0x2f,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/128K)"     },
-	{ 15, -1, -1, 15, 0x2f,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Palermo/256K)"     },
-	{ 15, -1, -1, 15, 0x4f,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Manila/128K)"      },
-	{ 15, -1, -1, 15, 0x4f,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Manila/256K)"      },
-	{ 15, -1, -1, 15, 0x5f,   1,   128,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Manila/128K)"      },
-	{ 15, -1, -1, 15, 0x5f,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Manila/256K)"      },
-	{ 15, -1, -1, 15, 0x6b,   2,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 Dual (Sherman/256K)"},
-	{ 15, -1, -1, 15, 0x6b,   2,   512,    -1, NC, SEMPRON_            ,     0, "Sempron 64 Dual (Sherman/512K)"},
-	{ 15, -1, -1, 15, 0x7f,   1,   256,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Sparta/256K)"      },
-	{ 15, -1, -1, 15, 0x7f,   1,   512,    -1, NC, SEMPRON_            ,     0, "Sempron 64 (Sparta/512K)"      },
-	{ 15, -1, -1, 15, 0x4c,   1,   256,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Keene/256K)"},
-	{ 15, -1, -1, 15, 0x4c,   1,   512,    -1, NC, MOBILE_| SEMPRON_   ,     0, "Mobile Sempron 64 (Keene/512K)"},
-	{ 15, -1, -1, 15,   -1,   2,    -1,    -1, NC, SEMPRON_            ,     0, "Sempron Dual Core"             },
-	
-	{ 15, -1, -1, 15, 0x24,   1,   512,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (Lancaster/512K)"    },
-	{ 15, -1, -1, 15, 0x24,   1,  1024,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (Lancaster/1024K)"   },
-	{ 15, -1, -1, 15, 0x48,   2,   256,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Taylor)"            },
-	{ 15, -1, -1, 15, 0x48,   2,   512,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Trinidad)"          },
-	{ 15, -1, -1, 15, 0x4c,   1,   512,    -1, NC, TURION_|_64_        ,     0, "Turion 64 (Richmond)"          },
-	{ 15, -1, -1, 15, 0x68,   2,   256,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Tyler/256K)"        },
-	{ 15, -1, -1, 15, 0x68,   2,   512,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Tyler/512K)"        },
-	{ 15, -1, -1, 17,    3,   2,   512,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Griffin/512K)"      },
-	{ 15, -1, -1, 17,    3,   2,  1024,    -1, NC, TURION_|_X2         ,     0, "Turion X2 (Griffin/1024K)"     },
-
-	/* K10 Architecture (2007) */
-	{ 15, -1, -1, 16,   -1,   1,    -1,    -1, PHENOM, 0               ,     0, "Unknown AMD Phenom"            },
-	{ 15,  2, -1, 16,   -1,   1,    -1,    -1, PHENOM, 0               ,     0, "Phenom"                        },
-	{ 15,  2, -1, 16,   -1,   3,    -1,    -1, PHENOM, 0               ,     0, "Phenom X3 (Toliman)"           },
-	{ 15,  2, -1, 16,   -1,   4,    -1,    -1, PHENOM, 0               ,     0, "Phenom X4 (Agena)"             },
-	{ 15,  2, -1, 16,   -1,   3,   512,    -1, PHENOM, 0               ,     0, "Phenom X3 (Toliman/256K)"      },
-	{ 15,  2, -1, 16,   -1,   3,   512,    -1, PHENOM, 0               ,     0, "Phenom X3 (Toliman/512K)"      },
-	{ 15,  2, -1, 16,   -1,   4,   128,    -1, PHENOM, 0               ,     0, "Phenom X4 (Agena/128K)"        },
-	{ 15,  2, -1, 16,   -1,   4,   256,    -1, PHENOM, 0               ,     0, "Phenom X4 (Agena/256K)"        },
-	{ 15,  2, -1, 16,   -1,   4,   512,    -1, PHENOM,  0              ,     0, "Phenom X4 (Agena/512K)"        },
-	{ 15,  2, -1, 16,   -1,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon X2 (Kuma)"              },
-	/* Phenom II derivates: */
-	{ 15,  4, -1, 16,   -1,   4,    -1,    -1, NC, 0                   ,     0, "Phenom (Deneb-based)"          },
-	{ 15,  4, -1, 16,   -1,   1,  1024,    -1, NC, SEMPRON_            ,     0, "Sempron (Sargas)"              },
-	{ 15,  4, -1, 16,   -1,   2,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X2 (Callisto)"       },
-	{ 15,  4, -1, 16,   -1,   3,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X3 (Heka)"           },
-	{ 15,  4, -1, 16,   -1,   4,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X4"                  },
-	{ 15,  4, -1, 16,    4,   4,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X4 (Deneb)"          },
-	{ 15,  5, -1, 16,    5,   4,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X4 (Deneb)"          },
-	{ 15,  4, -1, 16,   10,   4,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X4 (Zosma)"          },
-	{ 15,  4, -1, 16,   10,   6,   512,    -1, PHENOM2, 0              ,     0, "Phenom II X6 (Thuban)"         },
-	/* Athlon II derivates: */
-	{ 15,  6, -1, 16,    6,   2,   512,    -1, NC, ATHLON_|_X2         ,     0, "Athlon II (Champlain)"         },
-	{ 15,  6, -1, 16,    6,   2,   512,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon II X2 (Regor)"          },
-	{ 15,  6, -1, 16,    6,   2,  1024,    -1, NC, ATHLON_|_64_|_X2    ,     0, "Athlon II X2 (Regor)"          },
-	{ 15,  5, -1, 16,    5,   3,   512,    -1, NC, ATHLON_|_64_|_X3    ,     0, "Athlon II X3 (Rana)"           },
-	{ 15,  5, -1, 16,    5,   4,   512,    -1, NC, ATHLON_|_64_|_X4    ,     0, "Athlon II X4 (Propus)"         },
-	/* Llano APUs (2011): */
-	{ 15,  1, -1, 18,    1,   2,    -1,    -1, FUSION_EA, 0            ,     0, "Llano X2"                      },
-	{ 15,  1, -1, 18,    1,   3,    -1,    -1, FUSION_EA, 0            ,     0, "Llano X3"                      },
-	{ 15,  1, -1, 18,    1,   4,    -1,    -1, FUSION_EA, 0            ,     0, "Llano X4"                      },
-
-	/* Family 14h: Bobcat Architecture (2011) */
-	{ 15,  2, -1, 20,   -1,   1,    -1,    -1, FUSION_C, 0             ,     0, "Brazos Ontario"                },
-	{ 15,  2, -1, 20,   -1,   2,    -1,    -1, FUSION_C, 0             ,     0, "Brazos Ontario (Dual-core)"    },
-	{ 15,  1, -1, 20,   -1,   1,    -1,    -1, FUSION_E, 0             ,     0, "Brazos Zacate"                 },
-	{ 15,  1, -1, 20,   -1,   2,    -1,    -1, FUSION_E, 0             ,     0, "Brazos Zacate (Dual-core)"     },
-	{ 15,  2, -1, 20,   -1,   2,    -1,    -1, FUSION_Z, 0             ,     0, "Brazos Desna (Dual-core)"      },
-
-	/* Family 15h: Bulldozer Architecture (2011) */
-	{ 15, -1, -1, 21,    0,   4,    -1,    -1, NC, 0                   ,     0, "Bulldozer X2"                  },
-	{ 15, -1, -1, 21,    1,   4,    -1,    -1, NC, 0                   ,     0, "Bulldozer X2"                  },
-	{ 15, -1, -1, 21,    1,   6,    -1,    -1, NC, 0                   ,     0, "Bulldozer X3"                  },
-	{ 15, -1, -1, 21,    1,   8,    -1,    -1, NC, 0                   ,     0, "Bulldozer X4"                  },
-	/* 2nd-gen, Piledriver core (2012): */
-	{ 15, -1, -1, 21,    2,   4,    -1,    -1, NC, 0                   ,     0, "Vishera X2"                    },
-	{ 15, -1, -1, 21,    2,   6,    -1,    -1, NC, 0                   ,     0, "Vishera X3"                    },
-	{ 15, -1, -1, 21,    2,   8,    -1,    -1, NC, 0                   ,     0, "Vishera X4"                    },
-	{ 15,  0, -1, 21,   16,   2,    -1,    -1, FUSION_A, 0             ,     0, "Trinity X2"                    },
-	{ 15,  0, -1, 21,   16,   4,    -1,    -1, FUSION_A, 0             ,     0, "Trinity X4"                    },
-	{ 15,  3, -1, 21,   19,   2,    -1,    -1, FUSION_A, 0             ,     0, "Richland X2"                   },
-	{ 15,  3, -1, 21,   19,   4,    -1,    -1, FUSION_A, 0             ,     0, "Richland X4"                   },
-	/* 3rd-gen, Steamroller core (2014): */
-	{ 15,  0, -1, 21,   48,   2,    -1,    -1, FUSION_A, 0             ,     0, "Kaveri X2"                     },
-	{ 15,  0, -1, 21,   48,   4,    -1,    -1, FUSION_A, 0             ,     0, "Kaveri X4"                     },
-	{ 15,  8, -1, 21,   56,   4,    -1,    -1, FUSION_A, 0             ,     0, "Godavari X4"                   },
-	/* 4th-gen, Excavator core (2015): */
-	{ 15,  1, -1, 21,   96,   2,    -1,    -1, FUSION_A, 0             ,     0, "Carrizo X2"                    },
-	{ 15,  1, -1, 21,   96,   4,    -1,    -1, FUSION_A, 0             ,     0, "Carrizo X4"                    },
-	{ 15,  5, -1, 21,  101,   2,    -1,    -1, FUSION_A, 0             ,     0, "Bristol Ridge X2"              },
-	{ 15,  5, -1, 21,  101,   4,    -1,    -1, FUSION_A, 0             ,     0, "Bristol Ridge X4"              },
-	{ 15,  0, -1, 21,  112,   2,    -1,    -1, FUSION_A, 0             ,     0, "Stoney Ridge X2"               },
-	{ 15,  0, -1, 21,  112,   2,    -1,    -1, FUSION_E, 0             ,     0, "Stoney Ridge X2"               },
-
-	/* Family 16h: Jaguar Architecture (2013) */
-	{ 15,  0, -1, 22,    0,   2,    -1,    -1, FUSION_A, 0             ,     0, "Kabini X2"                     },
-	{ 15,  0, -1, 22,    0,   4,    -1,    -1, FUSION_A, 0             ,     0, "Kabini X4"                     },
-	/* 2nd-gen, Puma core (2013): */
-	{ 15,  0, -1, 22,   48,   2,    -1,    -1, FUSION_E, 0             ,     0, "Mullins X2"                    },
-	{ 15,  0, -1, 22,   48,   4,    -1,    -1, FUSION_A, 0             ,     0, "Mullins X4"                    },
-
-	/* Family 17h: Zen Architecture (2017) */
-	{ 15, -1, -1, 23,    1,   8,    -1,    -1, NC, 0                   ,     0, "Ryzen 7"                       },
-	{ 15, -1, -1, 23,    1,   6,    -1,    -1, NC, 0                   , _1600, "Ryzen 5"                       },
-	{ 15, -1, -1, 23,    1,   4,    -1,    -1, NC, 0                   , _1500, "Ryzen 5"                       },
-	{ 15, -1, -1, 23,    1,   4,    -1,    -1, NC, 0                   , _1400, "Ryzen 5"                       },
-	{ 15, -1, -1, 23,    1,   4,    -1,    -1, NC, 0                   ,     0, "Ryzen 3"                       },
-	//{ 15, -1, -1, 23,    1,   4,    -1,    -1, NC, 0                   ,     0, "Raven Ridge"                   }, //TBA
-
-	/* Newer Opterons: */
-	{ 15,  9, -1, 22,    9,   8,    -1,    -1, NC, OPTERON_            ,     0, "Magny-Cours Opteron"           },
-};
-
-
-static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
-{
-	const struct feature_map_t matchtable_edx81[] = {
-		{ 20, CPU_FEATURE_NX },
-		{ 22, CPU_FEATURE_MMXEXT },
-		{ 25, CPU_FEATURE_FXSR_OPT },
-		{ 30, CPU_FEATURE_3DNOWEXT },
-		{ 31, CPU_FEATURE_3DNOW },
-	};
-	const struct feature_map_t matchtable_ecx81[] = {
-		{  1, CPU_FEATURE_CMP_LEGACY },
-		{  2, CPU_FEATURE_SVM },
-		{  5, CPU_FEATURE_ABM },
-		{  6, CPU_FEATURE_SSE4A },
-		{  7, CPU_FEATURE_MISALIGNSSE },
-		{  8, CPU_FEATURE_3DNOWPREFETCH },
-		{  9, CPU_FEATURE_OSVW },
-		{ 10, CPU_FEATURE_IBS },
-		{ 11, CPU_FEATURE_XOP },
-		{ 12, CPU_FEATURE_SKINIT },
-		{ 13, CPU_FEATURE_WDT },
-		{ 16, CPU_FEATURE_FMA4 },
-		{ 21, CPU_FEATURE_TBM },
-	};
-	const struct feature_map_t matchtable_edx87[] = {
-		{  0, CPU_FEATURE_TS },
-		{  1, CPU_FEATURE_FID },
-		{  2, CPU_FEATURE_VID },
-		{  3, CPU_FEATURE_TTP },
-		{  4, CPU_FEATURE_TM_AMD },
-		{  5, CPU_FEATURE_STC },
-		{  6, CPU_FEATURE_100MHZSTEPS },
-		{  7, CPU_FEATURE_HWPSTATE },
-		/* id 8 is handled in common */
-		{  9, CPU_FEATURE_CPB },
-		{ 10, CPU_FEATURE_APERFMPERF },
-		{ 11, CPU_FEATURE_PFI },
-		{ 12, CPU_FEATURE_PA },
-	};
-	if (raw->ext_cpuid[0][0] >= 0x80000001) {
-		match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data);
-		match_features(matchtable_ecx81, COUNT_OF(matchtable_ecx81), raw->ext_cpuid[1][2], data);
-	}
-	if (raw->ext_cpuid[0][0] >= 0x80000007)
-		match_features(matchtable_edx87, COUNT_OF(matchtable_edx87), raw->ext_cpuid[7][3], data);
-	if (raw->ext_cpuid[0][0] >= 0x8000001a) {
-		/* We have the extended info about SSE unit size */
-		data->detection_hints[CPU_HINT_SSE_SIZE_AUTH] = 1;
-		data->sse_size = (raw->ext_cpuid[0x1a][0] & 1) ? 128 : 64;
-	}
-}
-
-static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
-{
-	int l3_result;
-	const int assoc_table[16] = {
-		0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, 255
-	};
-	unsigned n = raw->ext_cpuid[0][0];
-	
-	if (n >= 0x80000005) {
-		data->l1_data_cache = (raw->ext_cpuid[5][2] >> 24) & 0xff;
-		data->l1_assoc = (raw->ext_cpuid[5][2] >> 16) & 0xff;
-		data->l1_cacheline = (raw->ext_cpuid[5][2]) & 0xff;
-		data->l1_instruction_cache = (raw->ext_cpuid[5][3] >> 24) & 0xff;
-	}
-	if (n >= 0x80000006) {
-		data->l2_cache = (raw->ext_cpuid[6][2] >> 16) & 0xffff;
-		data->l2_assoc = assoc_table[(raw->ext_cpuid[6][2] >> 12) & 0xf];
-		data->l2_cacheline = (raw->ext_cpuid[6][2]) & 0xff;
-		
-		l3_result = (raw->ext_cpuid[6][3] >> 18);
-		if (l3_result > 0) {
-			l3_result = 512 * l3_result; /* AMD spec says it's a range,
-			                                but we take the lower bound */
-			data->l3_cache = l3_result;
-			data->l3_assoc = assoc_table[(raw->ext_cpuid[6][3] >> 12) & 0xf];
-			data->l3_cacheline = (raw->ext_cpuid[6][3]) & 0xff;
-		} else {
-			data->l3_cache = 0;
-		}
-	}
-}
-
-static void decode_amd_number_of_cores(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
-{
-	int logical_cpus = -1, num_cores = -1;
-	
-	if (raw->basic_cpuid[0][0] >= 1) {
-		logical_cpus = (raw->basic_cpuid[1][1] >> 16) & 0xff;
-		if (raw->ext_cpuid[0][0] >= 8) {
-			num_cores = 1 + (raw->ext_cpuid[8][2] & 0xff);
-		}
-	}
-	if (data->flags[CPU_FEATURE_HT]) {
-		if (num_cores > 1) {
-			if (data->ext_family >= 23)
-				num_cores /= 2; // e.g., Ryzen 7 reports 16 "real" cores, but they are really just 8.
-			data->num_cores = num_cores;
-			data->num_logical_cpus = logical_cpus;
-		} else {
-			data->num_cores = 1;
-			data->num_logical_cpus = (logical_cpus >= 2 ? logical_cpus : 2);
-		}
-	} else {
-		data->num_cores = data->num_logical_cpus = 1;
-	}
-}
-
-static int amd_has_turion_modelname(const char *bs)
-{
-	/* We search for something like TL-60. Ahh, I miss regexes...*/
-	int i, l, k;
-	char code[3] = {0};
-	const char* codes[] = { "ML", "MT", "MK", "TK", "TL", "RM", "ZM", "" };
-	l = (int) strlen(bs);
-	for (i = 3; i < l - 2; i++) {
-		if (bs[i] == '-' &&
-		    isupper(bs[i-1]) && isupper(bs[i-2]) && !isupper(bs[i-3]) &&
-		    isdigit(bs[i+1]) && isdigit(bs[i+2]) && !isdigit(bs[i+3]))
-		{
-			code[0] = bs[i-2];
-			code[1] = bs[i-1];
-			for (k = 0; codes[k][0]; k++)
-				if (!strcmp(codes[k], code)) return 1;
-		}
-	}
-	return 0;
-}
-
-static struct amd_code_and_bits_t decode_amd_codename_part1(const char *bs)
-{
-	amd_code_t code = NC;
-	uint64_t bits = 0;
-	struct amd_code_and_bits_t result;
-
-	if (strstr(bs, "Dual Core") ||
-	    strstr(bs, "Dual-Core") ||
-	    strstr(bs, " X2 "))
-		bits |= _X2;
-	if (strstr(bs, " X4 ")) bits |= _X4;
-	if (strstr(bs, " X3 ")) bits |= _X3;
-	if (strstr(bs, "Opteron")) bits |= OPTERON_;
-	if (strstr(bs, "Phenom")) {
-		code = (strstr(bs, "II")) ? PHENOM2 : PHENOM;
-	}
-	if (amd_has_turion_modelname(bs)) {
-		bits |= TURION_;
-	}
-	if (strstr(bs, "Athlon(tm)")) bits |= ATHLON_;
-	if (strstr(bs, "Sempron(tm)")) bits |= SEMPRON_;
-	if (strstr(bs, "Duron")) bits |= DURON_;
-	if (strstr(bs, " 64 ")) bits |= _64_;
-	if (strstr(bs, " FX")) bits |= _FX;
-	if (strstr(bs, " MP")) bits |= _MP_;
-	if (strstr(bs, "Athlon(tm) 64") || strstr(bs, "Athlon(tm) II X") || match_pattern(bs, "Athlon(tm) X#")) {
-		bits |= ATHLON_ | _64_;
-	}
-	if (strstr(bs, "Turion")) bits |= TURION_;
-	
-	if (strstr(bs, "mobile") || strstr(bs, "Mobile")) {
-		bits |= MOBILE_;
-	}
-	
-	if (strstr(bs, "XP")) bits |= _XP_;
-	if (strstr(bs, "XP-M")) bits |= _M_;
-	if (strstr(bs, "(LV)")) bits |= _LV_;
-
-	if (match_pattern(bs, "C-##")) code = FUSION_C;
-	if (match_pattern(bs, "E-###")) code = FUSION_E;
-	if (match_pattern(bs, "Z-##")) code = FUSION_Z;
-	if (match_pattern(bs, "E#-####") || match_pattern(bs, "A#-####")) code = FUSION_EA;
-
-	result.code = code;
-	result.bits = bits;
-	return result;
-}
-
-static int decode_amd_ryzen_model_code(const char* bs)
-{
-	const struct {
-		int model_code;
-		const char* match_str;
-	} patterns[] = {
-		{ _1600, "1600" },
-		{ _1500, "1500" },
-		{ _1400, "1400" },
-	};
-	int i;
-
-	for (i = 0; i < COUNT_OF(patterns); i++)
-		if (strstr(bs, patterns[i].match_str))
-			return patterns[i].model_code;
-	//
-	return 0;
-}
-
-static void decode_amd_codename(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal)
-{
-	struct amd_code_and_bits_t code_and_bits = decode_amd_codename_part1(data->brand_str);
-	int i = 0;
-	char* code_str = NULL;
-	int model_code;
-
-	for (i = 0; i < COUNT_OF(amd_code_str); i++) {
-		if (code_and_bits.code == amd_code_str[i].code) {
-			code_str = amd_code_str[i].str;
-			break;
-		}
-	}
-	if (/*code == ATHLON_64_X2*/ match_all(code_and_bits.bits, ATHLON_|_64_|_X2) && data->l2_cache < 512) {
-		code_and_bits.bits &= ~(ATHLON_ | _64_);
-		code_and_bits.bits |= SEMPRON_;
-	}
-	if (code_str)
-		debugf(2, "Detected AMD brand code: %d (%s)\n", code_and_bits.code, code_str);
-	else
-		debugf(2, "Detected AMD brand code: %d\n", code_and_bits.code);
-
-	if (code_and_bits.bits) {
-		debugf(2, "Detected AMD bits: ");
-		debug_print_lbits(2, code_and_bits.bits);
-	}
-	// is it Ryzen? if so, we need to detect discern between the four-core 1400/1500 (Ryzen 5) and the four-core Ryzen 3:
-	model_code = (data->ext_family == 23) ? decode_amd_ryzen_model_code(data->brand_str) : 0;
-
-	internal->code.amd = code_and_bits.code;
-	internal->bits = code_and_bits.bits;
-	internal->score = match_cpu_codename(cpudb_amd, COUNT_OF(cpudb_amd), data, code_and_bits.code,
-	                                     code_and_bits.bits, model_code);
-}
-
-int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal)
-{
-	load_amd_features(raw, data);
-	decode_amd_cache_info(raw, data);
-	decode_amd_number_of_cores(raw, data);
-	decode_amd_codename(raw, data, internal);
-	return 0;
-}
-
-void cpuid_get_list_amd(struct cpu_list_t* list)
-{
-	generic_get_cpu_list(cpudb_amd, COUNT_OF(cpudb_amd), list);
-}
diff --git a/compat/libcpuid/recog_intel.c b/compat/libcpuid/recog_intel.c
deleted file mode 100644
index 1d6c6a840..000000000
--- a/compat/libcpuid/recog_intel.c
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Copyright 2008  Veselin Georgiev,
- * anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
- *
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <string.h>
-#include <ctype.h>
-#include "libcpuid.h"
-#include "libcpuid_util.h"
-#include "libcpuid_internal.h"
-#include "recog_intel.h"
-
-const struct intel_bcode_str { intel_code_t code; char *str; } intel_bcode_str[] = {
-	#define CODE(x) { x, #x }
-	#define CODE2(x, y) CODE(x)
-	#include "intel_code_t.h"
-	#undef CODE
-};
-
-typedef struct {
-	int code;
-	uint64_t bits;
-} intel_code_and_bits_t;
-
-enum _intel_model_t {
-	UNKNOWN = -1,
-	_3000 = 100,
-	_3100,
-	_3200,
-	X3200,
-	_3300,
-	X3300,
-	_5100,
-	_5200,
-	_5300,
-	_5400,
-	_2xxx, /* Core i[357] 2xxx */
-	_3xxx, /* Core i[357] 3xxx */
-};
-typedef enum _intel_model_t intel_model_t;
-
-enum _intel_bits_t {
-	PENTIUM_                = LBIT(  0 ),
-	CELERON_                = LBIT(  1 ),
-	MOBILE_                 = LBIT(  2 ),
-	CORE_                   = LBIT(  3 ),
-	_I_                     = LBIT(  4 ),
-	_M_                     = LBIT(  5 ),
-	_3                      = LBIT(  6 ),
-	_5                      = LBIT(  7 ),
-	_7                      = LBIT(  8 ),
-	XEON_                   = LBIT(  9 ),
-	_MP                     = LBIT( 10 ),
-	ATOM_                   = LBIT( 11 ),
-	
-};
-typedef enum _intel_bits_t intel_bits_t;
-
-const struct match_entry_t cpudb_intel[] = {
-	{ -1, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Intel CPU"       },
-	
-	/* i486 */
-	{  4, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown i486"            },
-	{  4,  0, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX-25/33"           },
-	{  4,  1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX-50"              },
-	{  4,  2, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 SX"                 },
-	{  4,  3, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX2"                },
-	{  4,  4, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 SL"                 },
-	{  4,  5, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 SX2"                },
-	{  4,  7, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX2 WriteBack"      },
-	{  4,  8, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX4"                },
-	{  4,  9, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "i486 DX4 WriteBack"      },
-	
-	/* All Pentia:
-	   Pentium 1 */
-	{  5, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Pentium"         },
-	{  5,  0, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium A-Step"          },
-	{  5,  1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium 1 (0.8u)"        },
-	{  5,  2, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium 1 (0.35u)"       },
-	{  5,  3, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium OverDrive"       },
-	{  5,  4, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium 1 (0.35u)"       },
-	{  5,  7, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium 1 (0.35u)"       },
-	{  5,  8, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium MMX (0.25u)"     },
-	
-	/* Pentium 2 / 3 / M / Conroe / whatsnext - all P6 based. */
-	{  6, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown P6"              },
-	{  6,  0, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium Pro"             },
-	{  6,  1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium Pro"             },
-	{  6,  3, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium II (Klamath)"    },
-	{  6,  5, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium II (Deschutes)"  },
-	{  6,  5, -1, -1, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile Pentium II (Tonga)"},
-	{  6,  6, -1, -1, -1,   1,    -1,    -1, NC,0              ,     0, "Pentium II (Dixon)"      },
-	
-	{  6,  3, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-II Xeon (Klamath)"     },
-	{  6,  5, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-II Xeon (Drake)"       },
-	{  6,  6, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-II Xeon (Dixon)"       },
-		
-	{  6,  5, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-II Celeron (Covington)" },
-	{  6,  6, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-II Celeron (Mendocino)" },
-	
-	/* -------------------------------------------------- */
-	
-	{  6,  7, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium III (Katmai)"    },
-	{  6,  8, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium III (Coppermine)"},
-	{  6, 10, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium III (Coppermine)"},
-	{  6, 11, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium III (Tualatin)"  },
-	
-	{  6,  7, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-III Xeon (Tanner)"     },
-	{  6,  8, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-III Xeon (Cascades)"   },
-	{  6, 10, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-III Xeon (Cascades)"   },
-	{  6, 11, -1, -1, -1,   1,    -1,    -1, NC, XEON_         ,     0, "P-III Xeon (Tualatin)"   },
-	
-	{  6,  7, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-III Celeron (Katmai)"     },
-	{  6,  8, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-III Celeron (Coppermine)" },
-	{  6, 10, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-III Celeron (Coppermine)" },
-	{  6, 11, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-III Celeron (Tualatin)"   },
-	
-	/* Netburst based (Pentium 4 and later)
-	   classic P4s */
-	{ 15, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Pentium 4"       },
-	{ 15, -1, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "Unknown P-4 Celeron"     },
-	{ 15, -1, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Unknown Xeon"            },
-	
-	{ 15,  0, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Willamette)"  },
-	{ 15,  1, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Willamette)"  },
-	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Northwood)"   },
-	{ 15,  3, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Prescott)"    },
-	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Prescott)"    },
-	{ 15,  6, -1, 15, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium 4 (Cedar Mill)"  },
-	{ 15,  0, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Willamette)" },
-	{ 15,  1, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Willamette)" },
-	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Northwood)"  },
-	{ 15,  3, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Prescott)"   },
-	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Prescott)"   },
-	{ 15,  6, -1, 15, -1,   1,    -1,    -1, NC, MOBILE_|PENTIUM_,   0, "Mobile P-4 (Cedar Mill)" },
-	
-	/* server CPUs */
-	{ 15,  0, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Foster)"           },
-	{ 15,  1, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Foster)"           },
-	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Prestonia)"        },
-	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, XEON_|_MP     ,     0, "Xeon (Gallatin)"         },
-	{ 15,  3, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Nocona)"           },
-	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Nocona)"           },
-	{ 15,  4, -1, 15, -1,   1,    -1,    -1, IRWIN, XEON_      ,     0, "Xeon (Irwindale)"        },
-	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, XEON_|_MP     ,     0, "Xeon (Cranford)"         },
-	{ 15,  4, -1, 15, -1,   1,    -1,    -1, POTOMAC, XEON_    ,     0, "Xeon (Potomac)"          },
-	{ 15,  6, -1, 15, -1,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon (Dempsey)"          },
-	
-	/* Pentium Ds */
-	{ 15,  4,  4, 15, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium D (SmithField)"  },
-	{ 15,  4, -1, 15, -1,   1,    -1,    -1, PENTIUM_D, 0      ,     0, "Pentium D (SmithField)"  },
-	{ 15,  4,  7, 15, -1,   1,    -1,    -1, NC, 0             ,     0, "Pentium D (SmithField)"  },
-	{ 15,  6, -1, 15, -1,   1,    -1,    -1, PENTIUM_D, 0      ,     0, "Pentium D (Presler)"     },
-
-	/* Celeron and Celeron Ds */
-	{ 15,  1, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron (Willamette)"   },
-	{ 15,  2, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron (Northwood)"    },
-	{ 15,  3, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron D (Prescott)"   },
-	{ 15,  4, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron D (Prescott)"   },
-	{ 15,  6, -1, 15, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "P-4 Celeron D (Cedar Mill)" },
-	
-	/* -------------------------------------------------- */
-	/* Intel Core microarchitecture - P6-based */
-	
-	{  6,  9, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Pentium M"          },
-	{  6,  9, -1, -1, -1,   1,    -1,    -1, PENTIUM_M, 0      ,     0, "Unknown Pentium M"          },
-	{  6,  9, -1, -1, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium M (Banias)"         },
-	{  6,  9, -1, -1, -1,   1,    -1,    -1, PENTIUM_M, 0      ,     0, "Pentium M (Banias)"         },
-	{  6,  9, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "Celeron M"                  },
-	{  6, 13, -1, -1, -1,   1,    -1,    -1, NC, PENTIUM_      ,     0, "Pentium M (Dothan)"         },
-	{  6, 13, -1, -1, -1,   1,    -1,    -1, PENTIUM_M, 0      ,     0, "Pentium M (Dothan)"         },
-	{  6, 13, -1, -1, -1,   1,    -1,    -1, NC, CELERON_      ,     0, "Celeron M"                  },
-	
-	{  6, 12, -1, -1, -1,  -1,    -1,    -1, NC, ATOM_         ,     0, "Unknown Atom"               },
-	{  6, 12, -1, -1, -1,  -1,    -1,    -1, DIAMONDVILLE,ATOM_,     0, "Atom (Diamondville)"        },
-	{  6, 12, -1, -1, -1,  -1,    -1,    -1, SILVERTHORNE,ATOM_,     0, "Atom (Silverthorne)"        },
-	{  6, 12, -1, -1, -1,  -1,    -1,    -1, CEDARVIEW, ATOM_  ,     0, "Atom (Cedarview)"           },
-	{  6,  6, -1, -1, -1,  -1,    -1,    -1, CEDARVIEW, ATOM_  ,     0, "Atom (Cedarview)"           },
-	{  6, 12, -1, -1, -1,  -1,    -1,    -1, PINEVIEW, ATOM_   ,     0, "Atom (Pineview)"            },
-	
-	/* -------------------------------------------------- */
-	
-	{  6, 14, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Yonah"             },
-	{  6, 14, -1, -1, -1,   1,    -1,    -1, CORE_SOLO, 0      ,     0, "Yonah (Core Solo)"         },
-	{  6, 14, -1, -1, -1,   2,    -1,    -1, CORE_DUO, 0       ,     0, "Yonah (Core Duo)"          },
-	{  6, 14, -1, -1, -1,   1,    -1,    -1, CORE_SOLO, MOBILE_,     0, "Yonah (Core Solo)"         },
-	{  6, 14, -1, -1, -1,   2,    -1,    -1, CORE_DUO , MOBILE_,     0, "Yonah (Core Duo)"          },
-	{  6, 14, -1, -1, -1,   1,    -1,    -1, CORE_SOLO, 0      ,     0, "Yonah (Core Solo)"         },
-	
-	{  6, 15, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Unknown Core 2"            },
-	{  6, 15, -1, -1, -1,   2,  4096,    -1, CORE_DUO, 0       ,     0, "Conroe (Core 2 Duo)"       },
-	{  6, 15, -1, -1, -1,   2,  1024,    -1, CORE_DUO, 0       ,     0, "Conroe (Core 2 Duo) 1024K" },
-	{  6, 15, -1, -1, -1,   2,   512,    -1, CORE_DUO, 0       ,     0, "Conroe (Core 2 Duo) 512K"  },
-	{  6, 15, -1, -1, -1,   4,    -1,    -1, QUAD_CORE, 0      ,     0, "Kentsfield (Core 2 Quad)"  },
-	{  6, 15, -1, -1, -1,   4,  4096,    -1, QUAD_CORE, 0      ,     0, "Kentsfield (Core 2 Quad)"  },
-	{  6, 15, -1, -1, -1, 400,    -1,    -1, MORE_THAN_QUADCORE, 0,  0, "More than quad-core"       },
-	{  6, 15, -1, -1, -1,   2,  2048,    -1, CORE_DUO, 0       ,     0, "Allendale (Core 2 Duo)"    },
-	{  6, 15, -1, -1, -1,   2,    -1,    -1, MOBILE_CORE_DUO, 0,     0, "Merom (Core 2 Duo)"        },
-	{  6, 15, -1, -1, -1,   2,  2048,    -1, MEROM, 0          ,     0, "Merom (Core 2 Duo) 2048K"  },
-	{  6, 15, -1, -1, -1,   2,  4096,    -1, MEROM, 0          ,     0, "Merom (Core 2 Duo) 4096K"  },
-	
-	{  6, 15, -1, -1, 15,   1,    -1,    -1, NC, CELERON_      ,     0, "Conroe-L (Celeron)"        },
-	{  6,  6, -1, -1, 22,   1,    -1,    -1, NC, CELERON_      ,     0, "Conroe-L (Celeron)"        },
-	{  6, 15, -1, -1, 15,   2,    -1,    -1, NC, CELERON_      ,     0, "Conroe-L (Allendale)"      },
-	{  6,  6, -1, -1, 22,   2,    -1,    -1, NC, CELERON_      ,     0, "Conroe-L (Allendale)"      },
-	
-	
-	{  6,  6, -1, -1, 22,   1,    -1,    -1, NC, 0             ,     0, "Unknown Core ?"           },
-	{  6,  7, -1, -1, 23,   1,    -1,    -1, NC, 0             ,     0, "Unknown Core ?"           },
-	{  6,  6, -1, -1, 22, 400,    -1,    -1, MORE_THAN_QUADCORE, 0,  0, "More than quad-core"      },
-	{  6,  7, -1, -1, 23, 400,    -1,    -1, MORE_THAN_QUADCORE, 0,  0, "More than quad-core"      },
-	
-	{  6,  7, -1, -1, 23,   1,    -1,    -1, CORE_SOLO         , 0,  0, "Unknown Core 45nm"        },
-	{  6,  7, -1, -1, 23,   1,    -1,    -1, CORE_DUO          , 0,  0, "Unknown Core 45nm"        },
-	{  6,  7, -1, -1, 23,   2,  1024,    -1, WOLFDALE          , 0,  0, "Celeron Wolfdale 1M"      },
-	{  6,  7, -1, -1, 23,   2,  2048,    -1, WOLFDALE          , 0,  0, "Wolfdale (Core 2 Duo) 2M" },
-	{  6,  7, -1, -1, 23,   2,  3072,    -1, WOLFDALE          , 0,  0, "Wolfdale (Core 2 Duo) 3M" },
-	{  6,  7, -1, -1, 23,   2,  6144,    -1, WOLFDALE          , 0,  0, "Wolfdale (Core 2 Duo) 6M" },
-	{  6,  7, -1, -1, 23,   1,    -1,    -1, MOBILE_CORE_DUO   , 0,  0, "Penryn (Core 2 Duo)"      },
-	{  6,  7, -1, -1, 23,   2,  1024,    -1, PENRYN            , 0,  0, "Penryn (Core 2 Duo)"      },
-	{  6,  7, -1, -1, 23,   2,  3072,    -1, PENRYN            , 0,  0, "Penryn (Core 2 Duo) 3M"   },
-	{  6,  7, -1, -1, 23,   2,  6144,    -1, PENRYN            , 0,  0, "Penryn (Core 2 Duo) 6M"   },
-	{  6,  7, -1, -1, 23,   4,  2048,    -1, NC                , 0,  0, "Yorkfield (Core 2 Quad) 2M"},
-	{  6,  7, -1, -1, 23,   4,  3072,    -1, NC                , 0,  0, "Yorkfield (Core 2 Quad) 3M"},
-	{  6,  7, -1, -1, 23,   4,  6144,    -1, NC                , 0,  0, "Yorkfield (Core 2 Quad) 6M"},
-	
-	/* Core microarchitecture-based Xeons: */
-	{  6, 14, -1, -1, 14,   1,    -1,    -1, NC, XEON_         ,     0, "Xeon LV"                  },
-	{  6, 15, -1, -1, 15,   2,  4096,    -1, NC, XEON_         , _5100, "Xeon (Woodcrest)"         },
-	{  6, 15, -1, -1, 15,   2,  2048,    -1, NC, XEON_         , _3000, "Xeon (Conroe/2M)"         },
-	{  6, 15, -1, -1, 15,   2,  4096,    -1, NC, XEON_         , _3000, "Xeon (Conroe/4M)"         },
-	{  6, 15, -1, -1, 15,   4,  4096,    -1, NC, XEON_         , X3200, "Xeon (Kentsfield)"        },
-	{  6, 15, -1, -1, 15,   4,  4096,    -1, NC, XEON_         , _5300, "Xeon (Clovertown)"        },
-	{  6,  7, -1, -1, 23,   2,  6144,    -1, NC, XEON_         , _3100, "Xeon (Wolfdale)"          },
-	{  6,  7, -1, -1, 23,   2,  6144,    -1, NC, XEON_         , _5200, "Xeon (Wolfdale DP)"       },
-	{  6,  7, -1, -1, 23,   4,  6144,    -1, NC, XEON_         , _5400, "Xeon (Harpertown)"        },
-	{  6,  7, -1, -1, 23,   4,  3072,    -1, NC, XEON_         , X3300, "Xeon (Yorkfield/3M)"      },
-	{  6,  7, -1, -1, 23,   4,  6144,    -1, NC, XEON_         , X3300, "Xeon (Yorkfield/6M)"      },
-
-	/* Nehalem CPUs (45nm): */
-	{  6, 10, -1, -1, 26,   4,    -1,    -1, GAINESTOWN, XEON_ ,     0, "Gainestown (Xeon)"        },
-	{  6, 10, -1, -1, 26,   4,    -1,  4096, GAINESTOWN, XEON_ ,     0, "Gainestown 4M (Xeon)"     },
-	{  6, 10, -1, -1, 26,   4,    -1,  8192, GAINESTOWN, XEON_ ,     0, "Gainestown 8M (Xeon)"     },
-	{  6, 10, -1, -1, 26,   4,    -1,    -1, NC, XEON_|_7      ,     0, "Bloomfield (Xeon)"        },
-	{  6, 10, -1, -1, 26,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Bloomfield (Core i7)"     },
-	{  6, 10, -1, -1, 30,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Lynnfield (Core i7)"      },
-	{  6,  5, -1, -1, 37,   4,    -1,  8192, NC, CORE_|_I_|_5  ,     0, "Lynnfield (Core i5)"      },
-
-	/* Westmere CPUs (32nm): */
-	{  6,  5, -1, -1, 37,   2,    -1,    -1, NC, 0             ,     0, "Unknown Core i3/i5"       },
-	{  6, 12, -1, -1, 44,  -1,    -1,    -1, WESTMERE, XEON_   ,     0, "Westmere (Xeon)"          },
-	{  6, 12, -1, -1, 44,  -1,    -1, 12288, WESTMERE, XEON_   ,     0, "Gulftown (Xeon)"          },
-	{  6, 12, -1, -1, 44,   4,    -1, 12288, NC, CORE_|_I_|_7  ,     0, "Gulftown (Core i7)"       },
-	{  6,  5, -1, -1, 37,   2,    -1,  4096, NC, CORE_|_I_|_5  ,     0, "Clarkdale (Core i5)"      },
-	{  6,  5, -1, -1, 37,   2,    -1,  4096, NC, CORE_|_I_|_3  ,     0, "Clarkdale (Core i3)"      },
-	{  6,  5, -1, -1, 37,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Arrandale"                },
-	{  6,  5, -1, -1, 37,   2,    -1,  4096, NC, CORE_|_I_|_7  ,     0, "Arrandale (Core i7)"      },
-	{  6,  5, -1, -1, 37,   2,    -1,  3072, NC, CORE_|_I_|_5  ,     0, "Arrandale (Core i5)"      },
-	{  6,  5, -1, -1, 37,   2,    -1,  3072, NC, CORE_|_I_|_3  ,     0, "Arrandale (Core i3)"      },
-
-	/* Sandy Bridge CPUs (32nm): */
-	{  6, 10, -1, -1, 42,  -1,    -1,    -1, NC, 0             ,     0, "Unknown Sandy Bridge"     },
-	{  6, 10, -1, -1, 42,  -1,    -1,    -1, NC, XEON_         ,     0, "Sandy Bridge (Xeon)"      },
-	{  6, 10, -1, -1, 42,  -1,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Sandy Bridge (Core i7)"   },
-	{  6, 10, -1, -1, 42,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Sandy Bridge (Core i7)"   },
-	{  6, 10, -1, -1, 42,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Sandy Bridge (Core i5)"   },
-	{  6, 10, -1, -1, 42,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Sandy Bridge (Core i3)"   },
-	{  6, 10, -1, -1, 42,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Sandy Bridge (Pentium)"   },
-	{  6, 10, -1, -1, 42,   1,    -1,    -1, NC, CELERON_      ,     0, "Sandy Bridge (Celeron)"   },
-	{  6, 10, -1, -1, 42,   2,    -1,    -1, NC, CELERON_      ,     0, "Sandy Bridge (Celeron)"   },
-	{  6, 13, -1, -1, 45,  -1,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Sandy Bridge-E"           },
-	{  6, 13, -1, -1, 45,  -1,    -1,    -1, NC, XEON_         ,     0, "Sandy Bridge-E (Xeon)"    },
-
-	/* Ivy Bridge CPUs (22nm): */
-	{  6, 10, -1, -1, 58,  -1,    -1,    -1, NC, XEON_         ,     0, "Ivy Bridge (Xeon)"        },
-	{  6, 10, -1, -1, 58,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Ivy Bridge (Core i7)"     },
-	{  6, 10, -1, -1, 58,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Ivy Bridge (Core i5)"     },
-	{  6, 10, -1, -1, 58,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Ivy Bridge (Core i3)"     },
-	{  6, 10, -1, -1, 58,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Ivy Bridge (Pentium)"     },
-	{  6, 10, -1, -1, 58,   1,    -1,    -1, NC, CELERON_      ,     0, "Ivy Bridge (Celeron)"     },
-	{  6, 10, -1, -1, 58,   2,    -1,    -1, NC, CELERON_      ,     0, "Ivy Bridge (Celeron)"     },
-	{  6, 14, -1, -1, 62,  -1,    -1,    -1, NC, 0             ,     0, "Ivy Bridge-E"             },
-	
-	/* Haswell CPUs (22nm): */
-	{  6, 12, -1, -1, 60,  -1,    -1,    -1, NC, XEON_         ,     0, "Haswell (Xeon)"           },
-	{  6, 12, -1, -1, 60,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Haswell (Core i7)"        },
-	{  6,  5, -1, -1, 69,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Haswell (Core i7)"        },
-	{  6,  6, -1, -1, 70,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Haswell (Core i7)"        },
-	{  6, 12, -1, -1, 60,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Haswell (Core i5)"        },
-	{  6,  5, -1, -1, 69,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Haswell (Core i5)"        },
-	{  6, 12, -1, -1, 60,   2,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Haswell (Core i5)"        },
-	{  6,  5, -1, -1, 69,   2,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Haswell (Core i5)"        },
-	{  6, 12, -1, -1, 60,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Haswell (Core i3)"        },
-	{  6,  5, -1, -1, 69,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Haswell (Core i3)"        },
-	{  6, 12, -1, -1, 60,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Haswell (Pentium)"        },
-	{  6, 12, -1, -1, 60,   2,    -1,    -1, NC, CELERON_      ,     0, "Haswell (Celeron)"        },
-	{  6, 12, -1, -1, 60,   1,    -1,    -1, NC, CELERON_      ,     0, "Haswell (Celeron)"        },
-	{  6, 15, -1, -1, 63,  -1,    -1,    -1, NC, 0             ,     0, "Haswell-E"                },
-
-	/* Broadwell CPUs (14nm): */
-	{  6,  7, -1, -1, 71,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell (Core i7)"      },
-	{  6,  7, -1, -1, 71,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Broadwell (Core i5)"      },
-	{  6, 13, -1, -1, 61,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell-U (Core i7)"    },
-	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell-U (Core i7)"    },
-	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Broadwell-U (Core i5)"    },
-	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Broadwell-U (Core i3)"    },
-	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Broadwell-U (Pentium)"    },
-	{  6, 13, -1, -1, 61,   2,    -1,    -1, NC, CELERON_      ,     0, "Broadwell-U (Celeron)"    },
-	{  6, 13, -1, -1, 61,   2,    -1,    -1, NA, 0             ,     0, "Broadwell-U (Core M)"     },
-	{  6, 15, -1, -1, 79,  -1,    -1,    -1, NC, XEON_         ,     0, "Broadwell-E (Xeon)"       },
-	{  6, 15, -1, -1, 79,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Broadwell-E (Core i3)"    },
-	{  6, 15, -1, -1, 79,   2,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Broadwell-E (Core i5)"    },
-	{  6, 15, -1, -1, 79,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Broadwell-E (Core i5)"    },
-	{  6, 15, -1, -1, 79,   2,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell-E (Core i7)"    },
-	{  6, 15, -1, -1, 79,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Broadwell-E (Core i7)"    },
-
-	/* Skylake CPUs (14nm): */
-	{  6, 14, -1, -1, 94,  -1,    -1,    -1, NC, XEON_         ,     0, "Skylake (Xeon)"           },
-	{  6, 14, -1, -1, 94,   4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Skylake (Core i7)"        },
-	{  6, 14, -1, -1, 94,   4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Skylake (Core i5)"        },
-	{  6, 14, -1, -1, 94,   2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Skylake (Core i3)"        },
-	{  6, 14, -1, -1, 94,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Skylake (Pentium)"        },
-	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, PENTIUM_      ,     0, "Skylake (Pentium)"        },
-	{  6, 14, -1, -1, 94,   2,    -1,    -1, NC, CELERON_      ,     0, "Skylake (Celeron)"        },
-	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, CELERON_      ,     0, "Skylake (Celeron)"        },
-	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, CORE_|_M_|_7  ,     0, "Skylake (Core m7)"        },
-	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, CORE_|_M_|_5  ,     0, "Skylake (Core m5)"        },
-	{  6, 14, -1, -1, 78,   2,    -1,    -1, NC, CORE_|_M_|_3  ,     0, "Skylake (Core m3)"        },
-
-	/* Kaby Lake CPUs (14nm): */
-	{  6, 14, -1, -1, 158,  4,    -1,    -1, NC, CORE_|_I_|_7  ,     0, "Kaby Lake (Core i7)"      },
-	{  6, 14, -1, -1, 158,  4,    -1,    -1, NC, CORE_|_I_|_5  ,     0, "Kaby Lake (Core i5)"      },
-	{  6, 14, -1, -1, 158,  2,    -1,    -1, NC, CORE_|_I_|_3  ,     0, "Kaby Lake (Core i3)"      },
-	{  6, 14, -1, -1, 158,  2,    -1,    -1, NC, PENTIUM_      ,     0, "Kaby Lake (Pentium)"      },
-	{  6, 14, -1, -1, 158,  2,    -1,    -1, NC, CELERON_      ,     0, "Kaby Lake (Celeron)"      },
-	{  6, 14, -1, -1, 158,  2,    -1,    -1, NC, CORE_|_M_|_3  ,     0, "Kaby Lake (Core m3)"      },
-
-	/* Itaniums */
-	{  7, -1, -1, -1, -1,   1,    -1,    -1, NC, 0             ,     0, "Itanium"                  },
-	{ 15, -1, -1, 16, -1,   1,    -1,    -1, NC, 0             ,     0, "Itanium 2"                },
-};
-
-
-static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
-{
-	const struct feature_map_t matchtable_edx1[] = {
-		{ 18, CPU_FEATURE_PN },
-		{ 21, CPU_FEATURE_DTS },
-		{ 22, CPU_FEATURE_ACPI },
-		{ 27, CPU_FEATURE_SS },
-		{ 29, CPU_FEATURE_TM },
-		{ 30, CPU_FEATURE_IA64 },
-		{ 31, CPU_FEATURE_PBE },
-	};
-	const struct feature_map_t matchtable_ecx1[] = {
-		{  2, CPU_FEATURE_DTS64 },
-		{  4, CPU_FEATURE_DS_CPL },
-		{  5, CPU_FEATURE_VMX },
-		{  6, CPU_FEATURE_SMX },
-		{  7, CPU_FEATURE_EST },
-		{  8, CPU_FEATURE_TM2 },
-		{ 10, CPU_FEATURE_CID },
-		{ 14, CPU_FEATURE_XTPR },
-		{ 15, CPU_FEATURE_PDCM },
-		{ 18, CPU_FEATURE_DCA },
-		{ 21, CPU_FEATURE_X2APIC },
-	};
-	const struct feature_map_t matchtable_edx81[] = {
-		{ 20, CPU_FEATURE_XD },
-	};
-	const struct feature_map_t matchtable_ebx7[] = {
-		{  2, CPU_FEATURE_SGX },
-		{  4, CPU_FEATURE_HLE },
-		{ 11, CPU_FEATURE_RTM },
-		{ 16, CPU_FEATURE_AVX512F },
-		{ 17, CPU_FEATURE_AVX512DQ },
-		{ 18, CPU_FEATURE_RDSEED },
-		{ 19, CPU_FEATURE_ADX },
-		{ 26, CPU_FEATURE_AVX512PF },
-		{ 27, CPU_FEATURE_AVX512ER },
-		{ 28, CPU_FEATURE_AVX512CD },
-		{ 29, CPU_FEATURE_SHA_NI },
-		{ 30, CPU_FEATURE_AVX512BW },
-		{ 31, CPU_FEATURE_AVX512VL },
-	};
-	if (raw->basic_cpuid[0][0] >= 1) {
-		match_features(matchtable_edx1, COUNT_OF(matchtable_edx1), raw->basic_cpuid[1][3], data);
-		match_features(matchtable_ecx1, COUNT_OF(matchtable_ecx1), raw->basic_cpuid[1][2], data);
-	}
-	if (raw->ext_cpuid[0][0] >= 1) {
-		match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data);
-	}
-	// detect TSX/AVX512:
-	if (raw->basic_cpuid[0][0] >= 7) {
-		match_features(matchtable_ebx7, COUNT_OF(matchtable_ebx7), raw->basic_cpuid[7][1], data);
-	}
-}
-
-enum _cache_type_t {
-	L1I,
-	L1D,
-	L2,
-	L3,
-	L4
-};
-typedef enum _cache_type_t cache_type_t;
-
-static void check_case(uint8_t on, cache_type_t cache, int size, int assoc, int linesize, struct cpu_id_t* data)
-{
-	if (!on) return;
-	switch (cache) {
-		case L1I:
-			data->l1_instruction_cache = size;
-			break;
-		case L1D:
-			data->l1_data_cache = size;
-			data->l1_assoc = assoc;
-			data->l1_cacheline = linesize;
-			break;
-		case L2:
-			data->l2_cache = size;
-			data->l2_assoc = assoc;
-			data->l2_cacheline = linesize;
-			break;
-		case L3:
-			data->l3_cache = size;
-			data->l3_assoc = assoc;
-			data->l3_cacheline = linesize;
-			break;
-		case L4:
-			data->l4_cache = size;
-			data->l4_assoc = assoc;
-			data->l4_cacheline = linesize;
-			break;
-		default:
-			break;
-	}
-}
-
-static void decode_intel_oldstyle_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
-{
-	uint8_t f[256] = {0};
-	int reg, off;
-	uint32_t x;
-	for (reg = 0; reg < 4; reg++) {
-		x = raw->basic_cpuid[2][reg];
-		if (x & 0x80000000) continue;
-		for (off = 0; off < 4; off++) {
-			f[x & 0xff] = 1;
-			x >>= 8;
-		}
-	}
-	
-	check_case(f[0x06], L1I,      8,  4,  32, data);
-	check_case(f[0x08], L1I,     16,  4,  32, data);
-	check_case(f[0x0A], L1D,      8,  2,  32, data);
-	check_case(f[0x0C], L1D,     16,  4,  32, data);
-	check_case(f[0x22],  L3,    512,  4,  64, data);
-	check_case(f[0x23],  L3,   1024,  8,  64, data);
-	check_case(f[0x25],  L3,   2048,  8,  64, data);
-	check_case(f[0x29],  L3,   4096,  8,  64, data);
-	check_case(f[0x2C], L1D,     32,  8,  64, data);
-	check_case(f[0x30], L1I,     32,  8,  64, data);
-	check_case(f[0x39],  L2,    128,  4,  64, data);
-	check_case(f[0x3A],  L2,    192,  6,  64, data);
-	check_case(f[0x3B],  L2,    128,  2,  64, data);
-	check_case(f[0x3C],  L2,    256,  4,  64, data);
-	check_case(f[0x3D],  L2,    384,  6,  64, data);
-	check_case(f[0x3E],  L2,    512,  4,  64, data);
-	check_case(f[0x41],  L2,    128,  4,  32, data);
-	check_case(f[0x42],  L2,    256,  4,  32, data);
-	check_case(f[0x43],  L2,    512,  4,  32, data);
-	check_case(f[0x44],  L2,   1024,  4,  32, data);
-	check_case(f[0x45],  L2,   2048,  4,  32, data);
-	check_case(f[0x46],  L3,   4096,  4,  64, data);
-	check_case(f[0x47],  L3,   8192,  8,  64, data);
-	check_case(f[0x4A],  L3,   6144, 12,  64, data);
-	check_case(f[0x4B],  L3,   8192, 16,  64, data);
-	check_case(f[0x4C],  L3,  12288, 12,  64, data);
-	check_case(f[0x4D],  L3,  16384, 16,  64, data);
-	check_case(f[0x4E],  L2,   6144, 24,  64, data);
-	check_case(f[0x60], L1D,     16,  8,  64, data);
-	check_case(f[0x66], L1D,      8,  4,  64, data);
-	check_case(f[0x67], L1D,     16,  4,  64, data);
-	check_case(f[0x68], L1D,     32,  4,  64, data);
-	/* The following four entries are trace cache. Intel does not
-	 * specify a cache-line size, so we use -1 instead
-	 */
-	check_case(f[0x70], L1I,     12,  8,  -1, data);
-	check_case(f[0x71], L1I,     16,  8,  -1, data);
-	check_case(f[0x72], L1I,     32,  8,  -1, data);
-	check_case(f[0x73], L1I,     64,  8,  -1, data);
-	
-	check_case(f[0x78],  L2,   1024,  4,  64, data);
-	check_case(f[0x79],  L2,    128,  8,  64, data);
-	check_case(f[0x7A],  L2,    256,  8,  64, data);
-	check_case(f[0x7B],  L2,    512,  8,  64, data);
-	check_case(f[0x7C],  L2,   1024,  8,  64, data);
-	check_case(f[0x7D],  L2,   2048,  8,  64, data);
-	check_case(f[0x7F],  L2,    512,  2,  64, data);
-	check_case(f[0x82],  L2,    256,  8,  32, data);
-	check_case(f[0x83],  L2,    512,  8,  32, data);
-	check_case(f[0x84],  L2,   1024,  8,  32, data);
-	check_case(f[0x85],  L2,   2048,  8,  32, data);
-	check_case(f[0x86],  L2,    512,  4,  64, data);
-	check_case(f[0x87],  L2,   1024,  8,  64, data);
-	
-	if (f[0x49]) {
-		/* This flag is overloaded with two meanings. On Xeon MP
-		 * (family 0xf, model 0x6) this means L3 cache. On all other
-		 * CPUs (notably Conroe et al), this is L2 cache. In both cases
-		 * it means 4MB, 16-way associative, 64-byte line size.
-		 */
-		if (data->family == 0xf && data->model == 0x6) {
-			data->l3_cache = 4096;
-			data->l3_assoc = 16;
-			data->l3_cacheline = 64;
-		} else {
-			data->l2_cache = 4096;
-			data->l2_assoc = 16;
-			data->l2_cacheline = 64;
-		}
-	}
-	if (f[0x40]) {
-		/* Again, a special flag. It means:
-		 * 1) If no L2 is specified, then CPU is w/o L2 (0 KB)
-		 * 2) If L2 is specified by other flags, then, CPU is w/o L3.
-		 */
-		if (data->l2_cache == -1) {
-			data->l2_cache = 0;
-		} else {
-			data->l3_cache = 0;
-		}
-	}
-}
-
-static void decode_intel_deterministic_cache_info(struct cpu_raw_data_t* raw,
-                                                  struct cpu_id_t* data)
-{
-	int ecx;
-	int ways, partitions, linesize, sets, size, level, typenumber;
-	cache_type_t type;
-	for (ecx = 0; ecx < MAX_INTELFN4_LEVEL; ecx++) {
-		typenumber = raw->intel_fn4[ecx][0] & 0x1f;
-		if (typenumber == 0) break;
-		level = (raw->intel_fn4[ecx][0] >> 5) & 0x7;
-		if (level == 1 && typenumber == 1)
-			type = L1D;
-		else if (level == 1 && typenumber == 2)
-			type = L1I;
-		else if (level == 2 && typenumber == 3)
-			type = L2;
-		else if (level == 3 && typenumber == 3)
-			type = L3;
-		else if (level == 4 && typenumber == 3)
-			type = L4;
-		else {
-			warnf("deterministic_cache: unknown level/typenumber combo (%d/%d), cannot\n", level, typenumber);
-			warnf("deterministic_cache: recognize cache type\n");
-			continue;
-		}
-		ways = ((raw->intel_fn4[ecx][1] >> 22) & 0x3ff) + 1;
-		partitions = ((raw->intel_fn4[ecx][1] >> 12) & 0x3ff) + 1;
-		linesize = (raw->intel_fn4[ecx][1] & 0xfff) + 1;
-		sets = raw->intel_fn4[ecx][2] + 1;
-		size = ways * partitions * linesize * sets / 1024;
-		check_case(1, type, size, ways, linesize, data);
-	}
-}
-
-static int decode_intel_extended_topology(struct cpu_raw_data_t* raw,
-                                           struct cpu_id_t* data)
-{
-	int i, level_type, num_smt = -1, num_core = -1;
-	for (i = 0; i < MAX_INTELFN11_LEVEL; i++) {
-		level_type = (raw->intel_fn11[i][2] & 0xff00) >> 8;
-		switch (level_type) {
-			case 0x01:
-				num_smt = raw->intel_fn11[i][1] & 0xffff;
-				break;
-			case 0x02:
-				num_core = raw->intel_fn11[i][1] & 0xffff;
-				break;
-			default:
-				break;
-		}
-	}
-	if (num_smt == -1 || num_core == -1) return 0;
-	data->num_logical_cpus = num_core;
-	data->num_cores = num_core / num_smt;
-	// make sure num_cores is at least 1. In VMs, the CPUID instruction
-	// is rigged and may give nonsensical results, but we should at least
-	// avoid outputs like data->num_cores == 0.
-	if (data->num_cores <= 0) data->num_cores = 1;
-	return 1;
-}
-
-static void decode_intel_number_of_cores(struct cpu_raw_data_t* raw,
-                                         struct cpu_id_t* data)
-{
-	int logical_cpus = -1, num_cores = -1;
-	
-	if (raw->basic_cpuid[0][0] >= 11) {
-		if (decode_intel_extended_topology(raw, data)) return;
-	}
-	
-	if (raw->basic_cpuid[0][0] >= 1) {
-		logical_cpus = (raw->basic_cpuid[1][1] >> 16) & 0xff;
-		if (raw->basic_cpuid[0][0] >= 4) {
-			num_cores = 1 + ((raw->basic_cpuid[4][0] >> 26) & 0x3f);
-		}
-	}
-	if (data->flags[CPU_FEATURE_HT]) {
-		if (num_cores > 1) {
-			data->num_cores = num_cores;
-			data->num_logical_cpus = logical_cpus;
-		} else {
-			data->num_cores = 1;
-			data->num_logical_cpus = (logical_cpus >= 1 ? logical_cpus : 1);
-			if (data->num_logical_cpus == 1)
-				data->flags[CPU_FEATURE_HT] = 0;
-		}
-	} else {
-		data->num_cores = data->num_logical_cpus = 1;
-	}
-}
-
-static intel_code_and_bits_t get_brand_code_and_bits(struct cpu_id_t* data)
-{
-	intel_code_t code = (intel_code_t) NC;
-	intel_code_and_bits_t result;
-	uint64_t bits = 0;
-	int i = 0;
-	const char* bs = data->brand_str;
-	const char* s;
-	const struct { intel_code_t c; const char *search; } matchtable[] = {
-		{ PENTIUM_M, "Pentium(R) M" },
-		{ CORE_SOLO, "Pentium(R) Dual  CPU" },
-		{ CORE_SOLO, "Pentium(R) Dual-Core" },
-		{ PENTIUM_D, "Pentium(R) D" },
-		{ CORE_SOLO, "Genuine Intel(R) CPU" },
-		{ CORE_SOLO, "Intel(R) Core(TM)" },
-		{ DIAMONDVILLE, "CPU [N ][23]## " },
-		{ SILVERTHORNE, "CPU Z" },
-		{ PINEVIEW, "CPU [ND][45]## " },
-		{ CEDARVIEW, "CPU [ND]#### " },
-	};
-	
-	const struct { uint64_t bit; const char* search; } bit_matchtable[] = {
-		{ XEON_, "Xeon" },
-		{ _MP, " MP" },
-		{ ATOM_, "Atom(TM) CPU" },
-		{ MOBILE_, "Mobile" },
-		{ CELERON_, "Celeron" },
-		{ PENTIUM_, "Pentium" },
-	};
-	
-	for (i = 0; i < COUNT_OF(bit_matchtable); i++) {
-		if (match_pattern(bs, bit_matchtable[i].search))
-			bits |= bit_matchtable[i].bit;
-	}
-	
-	if ((i = match_pattern(bs, "Core(TM) [im][357]")) != 0) {
-		bits |= CORE_;
-		i--;
-		switch (bs[i + 9]) {
-			case 'i': bits |= _I_; break;
-			case 'm': bits |= _M_; break;
-		}
-		switch (bs[i + 10]) {
-			case '3': bits |= _3; break;
-			case '5': bits |= _5; break;
-			case '7': bits |= _7; break;
-		}
-	}
-	for (i = 0; i < COUNT_OF(matchtable); i++)
-		if (match_pattern(bs, matchtable[i].search)) {
-			code = matchtable[i].c;
-			break;
-		}
-	debugf(2, "intel matchtable result is %d\n", code);
-	if (bits & XEON_) {
-		if (match_pattern(bs, "W35##") || match_pattern(bs, "[ELXW]75##"))
-			bits |= _7;
-		else if (match_pattern(bs, "[ELXW]55##"))
-			code = GAINESTOWN;
-		else if (match_pattern(bs, "[ELXW]56##"))
-			code = WESTMERE;
-		else if (data->l3_cache > 0 && data->family == 16)
-			/* restrict by family, since later Xeons also have L3 ... */
-			code = IRWIN;
-	}
-	if (match_all(bits, XEON_ + _MP) && data->l3_cache > 0)
-		code = POTOMAC;
-	if (code == CORE_SOLO) {
-		s = strstr(bs, "CPU");
-		if (s) {
-			s += 3;
-			while (*s == ' ') s++;
-			if (*s == 'T')
-				bits |= MOBILE_;
-		}
-	}
-	if (code == CORE_SOLO) {
-		switch (data->num_cores) {
-			case 1: break;
-			case 2:
-			{
-				code = CORE_DUO;
-				if (data->num_logical_cpus > 2)
-					code = DUAL_CORE_HT;
-				break;
-			}
-			case 4:
-			{
-				code = QUAD_CORE;
-				if (data->num_logical_cpus > 4)
-					code = QUAD_CORE_HT;
-				break;
-			}
-			default:
-				code = MORE_THAN_QUADCORE; break;
-		}
-	}
-	
-	if (code == CORE_DUO && (bits & MOBILE_) && data->model != 14) {
-		if (data->ext_model < 23) {
-			code = MEROM;
-		} else {
-			code = PENRYN;
-		}
-	}
-	if (data->ext_model == 23 &&
-		(code == CORE_DUO || code == PENTIUM_D || (bits & CELERON_))) {
-		code = WOLFDALE;
-	}
-
-	result.code = code;
-	result.bits = bits;
-	return result;
-}
-
-static intel_model_t get_model_code(struct cpu_id_t* data)
-{
-	int i = 0;
-	int l = (int) strlen(data->brand_str);
-	const char *bs = data->brand_str;
-	int mod_flags = 0, model_no = 0, ndigs = 0;
-	/* If the CPU is a Core ix, then just return the model number generation: */
-	if ((i = match_pattern(bs, "Core(TM) i[357]")) != 0) {
-		i += 11;
-		if (i + 4 >= l) return UNKNOWN;
-		if (bs[i] == '2') return _2xxx;
-		if (bs[i] == '3') return _3xxx;
-		return UNKNOWN;
-	}
-	
-	/* For Core2-based Xeons: */
-	while (i < l - 3) {
-		if (bs[i] == 'C' && bs[i+1] == 'P' && bs[i+2] == 'U')
-			break;
-		i++;
-	}
-	if (i >= l - 3) return UNKNOWN;
-	i += 3;
-	while (i < l - 4 && bs[i] == ' ') i++;
-	if (i >= l - 4) return UNKNOWN;
-	while (i < l - 4 && !isdigit(bs[i])) {
-		if (bs[i] >= 'A' && bs[i] <= 'Z')
-			mod_flags |= (1 << (bs[i] - 'A'));
-		i++;
-	}
-	if (i >= l - 4) return UNKNOWN;
-	while (isdigit(bs[i])) {
-		ndigs++;
-		model_no = model_no * 10 + (int) (bs[i] - '0');
-		i++;
-	}
-	if (ndigs != 4) return UNKNOWN;
-#define HAVE(ch, flags) ((flags & (1 << ((int)(ch-'A')))) != 0)
-	switch (model_no / 100) {
-		case 30: return _3000;
-		case 31: return _3100;
-		case 32:
-		{
-			return (HAVE('X', mod_flags)) ? X3200 : _3200;
-		}
-		case 33:
-		{
-			return (HAVE('X', mod_flags)) ? X3300 : _3300;
-		}
-		case 51: return _5100;
-		case 52: return _5200;
-		case 53: return _5300;
-		case 54: return _5400;
-		default:
-			return UNKNOWN;
-	}
-#undef HAVE
-}
-
-static void decode_intel_sgx_features(const struct cpu_raw_data_t* raw, struct cpu_id_t* data)
-{
-	struct cpu_epc_t epc;
-	int i;
-	
-	if (raw->basic_cpuid[0][0] < 0x12) return; // no 12h leaf
-	if (raw->basic_cpuid[0x12][0] == 0) return; // no sub-leafs available, probably it's disabled by BIOS
-	
-	// decode sub-leaf 0:
-	if (raw->basic_cpuid[0x12][0] & 1) data->sgx.flags[INTEL_SGX1] = 1;
-	if (raw->basic_cpuid[0x12][0] & 2) data->sgx.flags[INTEL_SGX2] = 1;
-	if (data->sgx.flags[INTEL_SGX1] || data->sgx.flags[INTEL_SGX2])
-		data->sgx.present = 1;
-	data->sgx.misc_select = raw->basic_cpuid[0x12][1];
-	data->sgx.max_enclave_32bit = (raw->basic_cpuid[0x12][3]     ) & 0xff;
-	data->sgx.max_enclave_64bit = (raw->basic_cpuid[0x12][3] >> 8) & 0xff;
-	
-	// decode sub-leaf 1:
-	data->sgx.secs_attributes = raw->intel_fn12h[1][0] | (((uint64_t) raw->intel_fn12h[1][1]) << 32);
-	data->sgx.secs_xfrm       = raw->intel_fn12h[1][2] | (((uint64_t) raw->intel_fn12h[1][3]) << 32);
-	
-	// decode higher-order subleafs, whenever present:
-	data->sgx.num_epc_sections = -1;
-	for (i = 0; i < 1000000; i++) {
-		epc = cpuid_get_epc(i, raw);
-		if (epc.length == 0) {
-			debugf(2, "SGX: epc section request for %d returned null, no more EPC sections.\n", i);
-			data->sgx.num_epc_sections = i;
-			break;
-		}
-	}
-	if (data->sgx.num_epc_sections == -1) {
-		debugf(1, "SGX: warning: seems to be infinitude of EPC sections.\n");
-		data->sgx.num_epc_sections = 1000000;
-	}
-}
-
-struct cpu_epc_t cpuid_get_epc(int index, const struct cpu_raw_data_t* raw)
-{
-	uint32_t regs[4];
-	struct cpu_epc_t retval = {0, 0};
-	if (raw && index < MAX_INTELFN12H_LEVEL - 2) {
-		// this was queried already, use the data:
-		memcpy(regs, raw->intel_fn12h[2 + index], sizeof(regs));
-	} else {
-		// query this ourselves:
-		regs[0] = 0x12;
-		regs[2] = 2 + index;
-		regs[1] = regs[3] = 0;
-		cpu_exec_cpuid_ext(regs);
-	}
-	
-	// decode values:
-	if ((regs[0] & 0xf) == 0x1) {
-		retval.start_addr |= (regs[0] & 0xfffff000); // bits [12, 32) -> bits [12, 32)
-		retval.start_addr |= ((uint64_t) (regs[1] & 0x000fffff)) << 32; // bits [0, 20) -> bits [32, 52)
-		retval.length     |= (regs[2] & 0xfffff000); // bits [12, 32) -> bits [12, 32)
-		retval.length     |= ((uint64_t) (regs[3] & 0x000fffff)) << 32; // bits [0, 20) -> bits [32, 52)
-	}
-	return retval;
-}
-
-int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal)
-{
-	intel_code_and_bits_t brand;
-	intel_model_t model_code;
-	int i;
-	char* brand_code_str = NULL;
-
-	load_intel_features(raw, data);
-	if (raw->basic_cpuid[0][0] >= 4) {
-		/* Deterministic way is preferred, being more generic */
-		decode_intel_deterministic_cache_info(raw, data);
-	} else if (raw->basic_cpuid[0][0] >= 2) {
-		decode_intel_oldstyle_cache_info(raw, data);
-	}
-	decode_intel_number_of_cores(raw, data);
-
-	brand = get_brand_code_and_bits(data);
-	model_code = get_model_code(data);
-	for (i = 0; i < COUNT_OF(intel_bcode_str); i++) {
-		if (brand.code == intel_bcode_str[i].code) {
-			brand_code_str = intel_bcode_str[i].str;
-			break;
-		}
-	}
-	if (brand_code_str)
-		debugf(2, "Detected Intel brand code: %d (%s)\n", brand.code, brand_code_str);
-	else
-		debugf(2, "Detected Intel brand code: %d\n", brand.code);
-	if (brand.bits) {
-		debugf(2, "Detected Intel bits: ");
-		debug_print_lbits(2, brand.bits);
-	}
-	debugf(2, "Detected Intel model code: %d\n", model_code);
-	
-	internal->code.intel = brand.code;
-	internal->bits = brand.bits;
-	
-	if (data->flags[CPU_FEATURE_SGX]) {
-		debugf(2, "SGX seems to be present, decoding...\n");
-		// if SGX is indicated by the CPU, verify its presence:
-		decode_intel_sgx_features(raw, data);
-	}
-
-	internal->score = match_cpu_codename(cpudb_intel, COUNT_OF(cpudb_intel), data,
-		brand.code, brand.bits, model_code);
-	return 0;
-}
-
-void cpuid_get_list_intel(struct cpu_list_t* list)
-{
-	generic_get_cpu_list(cpudb_intel, COUNT_OF(cpudb_intel), list);
-}
diff --git a/crypto/hash.c b/crypto/hash.c
deleted file mode 100644
index f3a16f0c1..000000000
--- a/crypto/hash.c
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2012-2013 The Cryptonote developers
-// Distributed under the MIT/X11 software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "hash-ops.h"
-#include "c_keccak.h"
-
-void hash_permutation(union hash_state *state) {
-  keccakf((uint64_t*)state, 24);
-}
-
-void hash_process(union hash_state *state, const uint8_t *buf, size_t count) {
-  keccak1600(buf, count, (uint8_t*)state);
-}
-
-void cn_fast_hash(const void *data, size_t length, char *hash) {
-  union hash_state state;
-  hash_process(&state, data, length);
-  memcpy(hash, &state, HASH_SIZE);
-}
diff --git a/elist.h b/elist.h
deleted file mode 100644
index a13561843..000000000
--- a/elist.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _LINUX_LIST_H
-#define _LINUX_LIST_H
-
-/*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-struct list_head {
-	struct list_head *next, *prev;
-};
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
-	struct list_head name = LIST_HEAD_INIT(name)
-
-#define INIT_LIST_HEAD(ptr) do { \
-	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
-} while (0)
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *new,
-			      struct list_head *prev,
-			      struct list_head *next)
-{
-	next->prev = new;
-	new->next = next;
-	new->prev = prev;
-	prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void list_add(struct list_head *new, struct list_head *head)
-{
-	__list_add(new, head, head->next);
-}
-
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
-	__list_add(new, head->prev, head);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head *prev, struct list_head *next)
-{
-	next->prev = prev;
-	prev->next = next;
-}
-
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
- */
-static inline void list_del(struct list_head *entry)
-{
-	__list_del(entry->prev, entry->next);
-	entry->next = (void *) 0;
-	entry->prev = (void *) 0;
-}
-
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.
- */
-static inline void list_del_init(struct list_head *entry)
-{
-	__list_del(entry->prev, entry->next);
-	INIT_LIST_HEAD(entry);
-}
-
-/**
- * list_move - delete from one list and add as another's head
- * @list: the entry to move
- * @head: the head that will precede our entry
- */
-static inline void list_move(struct list_head *list, struct list_head *head)
-{
-        __list_del(list->prev, list->next);
-        list_add(list, head);
-}
-
-/**
- * list_move_tail - delete from one list and add as another's tail
- * @list: the entry to move
- * @head: the head that will follow our entry
- */
-static inline void list_move_tail(struct list_head *list,
-				  struct list_head *head)
-{
-        __list_del(list->prev, list->next);
-        list_add_tail(list, head);
-}
-
-/**
- * list_empty - tests whether a list is empty
- * @head: the list to test.
- */
-static inline int list_empty(struct list_head *head)
-{
-	return head->next == head;
-}
-
-static inline void __list_splice(struct list_head *list,
-				 struct list_head *head)
-{
-	struct list_head *first = list->next;
-	struct list_head *last = list->prev;
-	struct list_head *at = head->next;
-
-	first->prev = head;
-	head->next = first;
-
-	last->next = at;
-	at->prev = last;
-}
-
-/**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
-static inline void list_splice(struct list_head *list, struct list_head *head)
-{
-	if (!list_empty(list))
-		__list_splice(list, head);
-}
-
-/**
- * list_splice_init - join two lists and reinitialise the emptied list.
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- *
- * The list at @list is reinitialised
- */
-static inline void list_splice_init(struct list_head *list,
-				    struct list_head *head)
-{
-	if (!list_empty(list)) {
-		__list_splice(list, head);
-		INIT_LIST_HEAD(list);
-	}
-}
-
-/**
- * list_entry - get the struct for this entry
- * @ptr:	the &struct list_head pointer.
- * @type:	the type of the struct this is embedded in.
- * @member:	the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
-	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-
-/**
- * list_for_each	-	iterate over a list
- * @pos:	the &struct list_head to use as a loop counter.
- * @head:	the head for your list.
- */
-#define list_for_each(pos, head) \
-	for (pos = (head)->next; pos != (head); \
-        	pos = pos->next)
-/**
- * list_for_each_prev	-	iterate over a list backwards
- * @pos:	the &struct list_head to use as a loop counter.
- * @head:	the head for your list.
- */
-#define list_for_each_prev(pos, head) \
-	for (pos = (head)->prev; pos != (head); \
-        	pos = pos->prev)
-
-/**
- * list_for_each_safe	-	iterate over a list safe against removal of list entry
- * @pos:	the &struct list_head to use as a loop counter.
- * @n:		another &struct list_head to use as temporary storage
- * @head:	the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
-	for (pos = (head)->next, n = pos->next; pos != (head); \
-		pos = n, n = pos->next)
-
-/**
- * list_for_each_entry	-	iterate over list of given type
- * @pos:	the type * to use as a loop counter.
- * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
- */
-#define list_for_each_entry(pos, head, member)				\
-	for (pos = list_entry((head)->next, typeof(*pos), member);	\
-	     &pos->member != (head); 					\
-	     pos = list_entry(pos->member.next, typeof(*pos), member))
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos:	the type * to use as a loop counter.
- * @n:		another type * to use as temporary storage
- * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member)			\
-	for (pos = list_entry((head)->next, typeof(*pos), member),	\
-		n = list_entry(pos->member.next, typeof(*pos), member);	\
-	     &pos->member != (head); 					\
-	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
-
-/**
- * list_for_each_entry_continue -       iterate over list of given type
- *                      continuing after existing point
- * @pos:        the type * to use as a loop counter.
- * @head:       the head for your list.
- * @member:     the name of the list_struct within the struct.
- */
-#define list_for_each_entry_continue(pos, head, member)			\
-	for (pos = list_entry(pos->member.next, typeof(*pos), member),	\
-		     prefetch(pos->member.next);			\
-	     &pos->member != (head);					\
-	     pos = list_entry(pos->member.next, typeof(*pos), member),	\
-		     prefetch(pos->member.next))
-
-#endif
diff --git a/options.c b/options.c
deleted file mode 100644
index eb88bcb0f..000000000
--- a/options.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <jansson.h>
-#include <curl/curl.h>
-#include <getopt.h>
-
-#include "version.h"
-#include "utils/applog.h"
-#include "options.h"
-#include "cpu.h"
-#include "donate.h"
-#include "algo/cryptonight/cryptonight.h"
-
-
-int64_t opt_affinity      = -1L;
-int     opt_n_threads     = 0;
-int     opt_algo_variant  = 0;
-int     opt_retries       = 5;
-int     opt_retry_pause   = 5;
-int     opt_donate_level  = DONATE_LEVEL;
-int     opt_max_cpu_usage = 75;
-bool    opt_colors        = true;
-bool    opt_keepalive     = false;
-bool    opt_background    = false;
-bool    opt_double_hash   = false;
-bool    opt_safe          = false;
-bool    opt_nicehash      = false;
-char    *opt_url          = NULL;
-char    *opt_backup_url   = NULL;
-char    *opt_userpass     = NULL;
-char    *opt_user         = NULL;
-char    *opt_pass         = NULL;
-
-enum mining_algo opt_algo = ALGO_CRYPTONIGHT;
-
-
-static char const usage[] = "\
-Usage: " APP_ID " [OPTIONS]\n\
-Options:\n\
-  -a, --algo=ALGO       cryptonight (default) or cryptonight-lite\n\
-  -o, --url=URL         URL of mining server\n\
-  -b, --backup-url=URL  URL of backup mining server\n\
-  -O, --userpass=U:P    username:password pair for mining server\n\
-  -u, --user=USERNAME   username for mining server\n\
-  -p, --pass=PASSWORD   password for mining server\n\
-  -t, --threads=N       number of miner threads\n\
-  -v, --av=N            algorithm variation, 0 auto select\n\
-  -k, --keepalive       send keepalived for prevent timeout (need pool support)\n\
-  -r, --retries=N       number of times to retry before switch to backup server (default: 5)\n\
-  -R, --retry-pause=N   time to pause between retries (default: 5)\n\
-      --cpu-affinity    set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\
-      --no-color        disable colored output\n\
-      --donate-level=N  donate level, default 5%% (5 minutes in 100 minutes)\n\
-  -B, --background      run the miner in the background\n\
-  -c, --config=FILE     load a JSON-format configuration file\n\
-      --max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)\n\
-      --safe            safe adjust threads and av settings for current CPU\n\
-      --nicehash        enable nicehash support\n\
-  -h, --help            display this help and exit\n\
-  -V, --version         output version information and exit\n\
-";
-
-
-static char const short_options[] = "a:c:khBp:Px:r:R:s:t:T:o:u:O:v:Vb:";
-
-
-static struct option const options[] = {
-    { "algo",          1, NULL, 'a'  },
-    { "av",            1, NULL, 'v'  },
-    { "background",    0, NULL, 'B'  },
-    { "backup-url",    1, NULL, 'b'  },
-    { "config",        1, NULL, 'c'  },
-    { "cpu-affinity",  1, NULL, 1020 },
-    { "donate-level",  1, NULL, 1003 },
-    { "help",          0, NULL, 'h'  },
-    { "keepalive",     0, NULL ,'k'  },
-    { "max-cpu-usage", 1, NULL, 1004 },
-    { "nicehash",      0, NULL, 1006 },
-    { "no-color",      0, NULL, 1002 },
-    { "pass",          1, NULL, 'p'  },
-    { "retries",       1, NULL, 'r'  },
-    { "retry-pause",   1, NULL, 'R'  },
-    { "safe",          0, NULL, 1005 },
-    { "threads",       1, NULL, 't'  },
-    { "url",           1, NULL, 'o'  },
-    { "user",          1, NULL, 'u'  },
-    { "userpass",      1, NULL, 'O'  },
-    { "version",       0, NULL, 'V'  },
-    { 0, 0, 0, 0 }
-};
-
-
-static const char *algo_names[] = {
-    [ALGO_CRYPTONIGHT]      = "cryptonight",
-#   ifndef XMRIG_NO_AEON
-    [ALGO_CRYPTONIGHT_LITE] = "cryptonight-lite"
-#   endif
-};
-
-
-#ifndef XMRIG_NO_AEON
-static int get_cryptonight_lite_variant(int variant) {
-    if (variant <= AEON_AV0_AUTO || variant >= AEON_AV_MAX) {
-        return (cpu_info.flags & CPU_FLAG_AES) ? AEON_AV2_AESNI_DOUBLE : AEON_AV4_SOFT_AES_DOUBLE;
-    }
-
-    if (opt_safe && !(cpu_info.flags & CPU_FLAG_AES) && variant <= AEON_AV2_AESNI_DOUBLE) {
-        return variant + 2;
-    }
-
-    return variant;
-}
-#endif
-
-
-static int get_algo_variant(int algo, int variant) {
-#   ifndef XMRIG_NO_AEON
-    if (algo == ALGO_CRYPTONIGHT_LITE) {
-        return get_cryptonight_lite_variant(variant);
-    }
-#   endif
-
-    if (variant <= XMR_AV0_AUTO || variant >= XMR_AV_MAX) {
-        return (cpu_info.flags & CPU_FLAG_AES) ? XMR_AV1_AESNI : XMR_AV3_SOFT_AES;
-    }
-
-    if (opt_safe && !(cpu_info.flags & CPU_FLAG_AES) && variant <= XMR_AV2_AESNI_DOUBLE) {
-        return variant + 2;
-    }
-
-    return variant;
-}
-
-
-static void parse_config(json_t *config, char *ref);
-static char *parse_url(const char *arg);
-
-
-static void parse_arg(int key, char *arg) {
-    char *p;
-    int v;
-    uint64_t ul;
-
-    switch (key)
-    {
-    case 'a':
-        for (int i = 0; i < ARRAY_SIZE(algo_names); i++) {
-            if (algo_names[i] && !strcmp(arg, algo_names[i])) {
-                opt_algo = i;
-                break;
-            }
-
-#           ifndef XMRIG_NO_AEON
-            if (i == ARRAY_SIZE(algo_names) && !strcmp(arg, "cryptonight-light")) {
-                opt_algo = i = ALGO_CRYPTONIGHT_LITE;
-            }
-#           endif
-
-            if (i == ARRAY_SIZE(algo_names)) {
-                show_usage_and_exit(1);
-            }
-        }
-        break;
-
-    case 'O': /* --userpass */
-        p = strchr(arg, ':');
-        if (!p) {
-            show_usage_and_exit(1);
-        }
-
-        free(opt_userpass);
-        opt_userpass = strdup(arg);
-        free(opt_user);
-        opt_user = calloc(p - arg + 1, 1);
-        strncpy(opt_user, arg, p - arg);
-        free(opt_pass);
-        opt_pass = strdup(p + 1);
-        break;
-
-    case 'o': /* --url */
-        p = parse_url(arg);
-        if (p) {
-            free(opt_url);
-            opt_url = p;
-        }
-        break;
-
-    case 'b': /* --backup-url */
-        p = parse_url(arg);
-        if (p) {
-            free(opt_backup_url);
-            opt_backup_url = p;
-        }
-        break;
-
-    case 'u': /* --user */
-        free(opt_user);
-        opt_user = strdup(arg);
-        break;
-
-    case 'p': /* --pass */
-        free(opt_pass);
-        opt_pass = strdup(arg);
-        break;
-
-    case 'r': /* --retries */
-        v = atoi(arg);
-        if (v < 1 || v > 1000) {
-            show_usage_and_exit(1);
-        }
-
-        opt_retries = v;
-        break;
-
-    case 'R': /* --retry-pause */
-        v = atoi(arg);
-        if (v < 1 || v > 3600) {
-            show_usage_and_exit(1);
-        }
-
-        opt_retry_pause = v;
-        break;
-
-    case 't': /* --threads */
-        v = atoi(arg);
-        if (v < 1 || v > 1024) {
-            show_usage_and_exit(1);
-        }
-
-        opt_n_threads = v;
-        break;
-
-    case 1004: /* --max-cpu-usage */
-        v = atoi(arg);
-        if (v < 1 || v > 100) {
-            show_usage_and_exit(1);
-        }
-
-        opt_max_cpu_usage = v;
-        break;
-
-    case 1005: /* --safe */
-        opt_safe = true;
-        break;
-
-    case 'k': /* --keepalive */
-        opt_keepalive = true;
-        break;
-
-    case 'V': /* --version */
-        show_version_and_exit();
-        break;
-
-    case 'h': /* --help */
-        show_usage_and_exit(0);
-        break;
-
-    case 'c': { /* --config */
-        json_error_t err;
-        json_t *config = json_load_file(arg, 0, &err);
-
-        if (!json_is_object(config)) {
-            if (err.line < 0) {
-                applog(LOG_ERR, "%s\n", err.text);
-            }
-            else {
-                applog(LOG_ERR, "%s:%d: %s\n", arg, err.line, err.text);
-            }
-        } else {
-            parse_config(config, arg);
-            json_decref(config);
-        }
-        break;
-    }
-
-    case 'B': /* --background */
-        opt_background = true;
-        opt_colors = false;
-        break;
-
-    case 'v': /* --av */
-        v = atoi(arg);
-        if (v < 0 || v > 1000) {
-            show_usage_and_exit(1);
-        }
-
-        opt_algo_variant = v;
-        break;
-
-    case 1020: /* --cpu-affinity */
-        p  = strstr(arg, "0x");
-        ul = p ? strtoul(p, NULL, 16) : atol(arg);
-        if (ul > (1UL << cpu_info.total_logical_cpus) -1) {
-            ul = -1;
-        }
-
-        opt_affinity = ul;
-        break;
-
-    case 1002: /* --no-color */
-        opt_colors = false;
-        break;
-
-    case 1003: /* --donate-level */
-        v = atoi(arg);
-        if (v < 1 || v > 99) {
-            show_usage_and_exit(1);
-        }
-
-        opt_donate_level = v;
-        break;
-
-    case 1006: /* --nicehash */
-        opt_nicehash = true;
-        break;
-
-    default:
-        show_usage_and_exit(1);
-    }
-}
-
-
-static void parse_config(json_t *config, char *ref)
-{
-    int i;
-    char buf[16];
-    json_t *val;
-
-    applog(LOG_ERR, ref);
-
-    for (i = 0; i < ARRAY_SIZE(options); i++) {
-        if (!options[i].name) {
-            break;
-        }
-
-        val = json_object_get(config, options[i].name);
-        if (!val) {
-            continue;
-        }
-
-        if (options[i].has_arg && json_is_string(val)) {
-            char *s = strdup(json_string_value(val));
-            if (!s) {
-                break;
-            }
-
-            parse_arg(options[i].val, s);
-            free(s);
-        }
-        else if (options[i].has_arg && json_is_integer(val)) {
-            sprintf(buf, "%d", (int) json_integer_value(val));
-            parse_arg(options[i].val, buf);
-        }
-        else if (options[i].has_arg && json_is_real(val)) {
-            sprintf(buf, "%f", json_real_value(val));
-            parse_arg(options[i].val, buf);
-        }
-        else if (!options[i].has_arg) {
-            if (json_is_true(val)) {
-               parse_arg(options[i].val, "");
-            }
-        }
-        else {
-            applog(LOG_ERR, "JSON option %s invalid", options[i].name);
-        }
-    }
-}
-
-
-static char *parse_url(const char *arg)
-{
-    char *p = strstr(arg, "://");
-    if (p) {
-        if (strncasecmp(arg, "stratum+tcp://", 14)) {
-            show_usage_and_exit(1);
-        }
-
-        return strdup(arg);
-    }
-
-
-    if (!strlen(arg) || *arg == '/') {
-        show_usage_and_exit(1);
-    }
-
-    char *dest = malloc(strlen(arg) + 16);
-    sprintf(dest, "stratum+tcp://%s", arg);
-
-    return dest;
-}
-
-
-/**
- * Parse application command line via getopt.
- */
-void parse_cmdline(int argc, char *argv[]) {
-    opt_user = strdup("x");
-    opt_pass = strdup("x");
-
-    int key;
-
-    while (1) {
-        key = getopt_long(argc, argv, short_options, options, NULL);
-        if (key < 0) {
-            break;
-        }
-
-        parse_arg(key, optarg);
-    }
-
-    if (optind < argc) {
-        fprintf(stderr, "%s: unsupported non-option argument '%s'\n", argv[0], argv[optind]);
-        show_usage_and_exit(1);
-    }
-
-    if (!opt_url) {
-        applog_notime(LOG_ERR, "No pool URL supplied. Exiting.\n", argv[0]);
-        proper_exit(1);
-    }
-
-    if (strstr(opt_url, ".nicehash.com:") != NULL) {
-        opt_nicehash = true;
-    }
-
-    if (!opt_userpass) {
-        opt_userpass = malloc(strlen(opt_user) + strlen(opt_pass) + 2);
-        if (!opt_userpass) {
-            proper_exit(1);
-        }
-
-        sprintf(opt_userpass, "%s:%s", opt_user, opt_pass);
-    }
-
-    opt_algo_variant = get_algo_variant(opt_algo, opt_algo_variant);
-
-    if (!cryptonight_init(opt_algo_variant)) {
-        applog(LOG_ERR, "Cryptonight hash self-test failed. This might be caused by bad compiler optimizations.");
-        proper_exit(1);
-    }
-
-    if (!opt_n_threads) {
-        opt_n_threads = get_optimal_threads_count(opt_algo, opt_double_hash, opt_max_cpu_usage);
-    }
-
-    if (opt_safe) {
-        const int count = get_optimal_threads_count(opt_algo, opt_double_hash, opt_max_cpu_usage);
-        if (opt_n_threads > count) {
-            opt_n_threads = count;
-        }
-    }
-}
-
-
-void show_usage_and_exit(int status) {
-    if (status) {
-        fprintf(stderr, "Try \"" APP_ID "\" --help' for more information.\n");
-    }
-    else {
-        printf(usage);
-    }
-
-    proper_exit(status);
-}
-
-
-void show_version_and_exit(void) {
-    printf(APP_NAME " " APP_VERSION "\n built on " __DATE__
-
-    #ifdef __GNUC__
-    " with GCC");
-    printf(" %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
-    #endif
-
-    printf("\n features:"
-    #ifdef __i386__
-    " i386"
-    #endif
-    #ifdef __x86_64__
-    " x86_64"
-    #endif
-    #ifdef __AES__
-    " AES-NI"
-    #endif
-    "\n");
-
-    printf("\n%s\n", curl_version());
-    #ifdef JANSSON_VERSION
-    printf("libjansson/%s\n", JANSSON_VERSION);
-    #endif
-    proper_exit(0);
-}
-
-
-const char* get_current_algo_name(void) {
-    return algo_names[opt_algo];
-}
diff --git a/options.h b/options.h
deleted file mode 100644
index a14aaeeb4..000000000
--- a/options.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __OPTIONS_H__
-#define __OPTIONS_H__
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifndef ARRAY_SIZE
-#   define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-#endif
-
-
-enum mining_algo {
-    ALGO_CRYPTONIGHT,      /* CryptoNight (Monero) */
-    ALGO_CRYPTONIGHT_LITE, /* CryptoNight-Lite (AEON) */
-};
-
-
-enum xmr_algo_variant {
-    XMR_AV0_AUTO,
-    XMR_AV1_AESNI,
-    XMR_AV2_AESNI_DOUBLE,
-    XMR_AV3_SOFT_AES,
-    XMR_AV4_SOFT_AES_DOUBLE,
-    XMR_AV_MAX
-};
-
-
-#ifndef XMRIG_NO_AEON
-enum aeon_algo_variant {
-    AEON_AV0_AUTO,
-    AEON_AV1_AESNI,
-    AEON_AV2_AESNI_DOUBLE,
-    AEON_AV3_SOFT_AES,
-    AEON_AV4_SOFT_AES_DOUBLE,
-    AEON_AV_MAX
-};
-#endif
-
-
-extern bool opt_colors;
-extern bool opt_keepalive;
-extern bool opt_background;
-extern bool opt_double_hash;
-extern bool opt_safe;
-extern bool opt_nicehash;
-extern char *opt_url;
-extern char *opt_backup_url;
-extern char *opt_userpass;
-extern char *opt_user;
-extern char *opt_pass;
-extern int opt_n_threads;
-extern int opt_algo_variant;
-extern int opt_retry_pause;
-extern int opt_retries;
-extern int opt_donate_level;
-extern int opt_max_cpu_usage;
-extern int64_t opt_affinity;
-extern enum mining_algo opt_algo;
-
-void parse_cmdline(int argc, char *argv[]);
-void show_usage_and_exit(int status);
-void show_version_and_exit(void);
-const char* get_current_algo_name(void);
-
-extern void proper_exit(int reason);
-
-
-#endif /* __OPTIONS_H__ */
diff --git a/win/app.ico b/res/app.ico
similarity index 100%
rename from win/app.ico
rename to res/app.ico
diff --git a/win/app.rc b/res/app.rc
similarity index 96%
rename from win/app.rc
rename to res/app.rc
index cb47aa3ca..800ce2dd5 100644
--- a/win/app.rc
+++ b/res/app.rc
@@ -1,5 +1,5 @@
 #include <windows.h>
-#include "../version.h"
+#include "../src/version.h"
 
 IDI_ICON1    ICON    DISCARDABLE    "app.ico"
 
diff --git a/src/3rdparty/align.h b/src/3rdparty/align.h
new file mode 100644
index 000000000..b61179b90
--- /dev/null
+++ b/src/3rdparty/align.h
@@ -0,0 +1,33 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALIGN_H__
+#define __ALIGN_H__
+
+#ifdef _MSC_VER
+#   define VAR_ALIGN(x, decl) __declspec(align(x)) decl
+#else
+#   define VAR_ALIGN(x, decl) decl __attribute__ ((aligned(x)))
+#endif
+
+#endif /* __ALIGN_H__ */
diff --git a/src/3rdparty/getopt/getopt.h b/src/3rdparty/getopt/getopt.h
new file mode 100644
index 000000000..0cb88895d
--- /dev/null
+++ b/src/3rdparty/getopt/getopt.h
@@ -0,0 +1,653 @@
+#ifndef __GETOPT_H__
+/**
+ * DISCLAIMER
+ * This file is part of the mingw-w64 runtime package.
+ *
+ * The mingw-w64 runtime package and its code is distributed in the hope that it 
+ * will be useful but WITHOUT ANY WARRANTY.  ALL WARRANTIES, EXPRESSED OR 
+ * IMPLIED ARE HEREBY DISCLAIMED.  This includes but is not limited to 
+ * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+ /*
+ * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#pragma warning(disable:4996);
+
+#define __GETOPT_H__
+
+/* All the headers include this file. */
+#include <crtdefs.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define	REPLACE_GETOPT		/* use this getopt as the system getopt(3) */
+
+#ifdef REPLACE_GETOPT
+int	opterr = 1;		/* if error message should be printed */
+int	optind = 1;		/* index into parent argv vector */
+int	optopt = '?';		/* character checked for validity */
+#undef	optreset		/* see getopt.h */
+#define	optreset		__mingw_optreset
+int	optreset;		/* reset getopt */
+char    *optarg;		/* argument associated with option */
+#endif
+
+//extern int optind;		/* index of first non-option in argv      */
+//extern int optopt;		/* single option character, as parsed     */
+//extern int opterr;		/* flag to enable built-in diagnostics... */
+//				/* (user may set to zero, to suppress)    */
+//
+//extern char *optarg;		/* pointer to argument of current option  */
+
+#define PRINT_ERROR	((opterr) && (*options != ':'))
+
+#define FLAG_PERMUTE	0x01	/* permute non-options to the end of argv */
+#define FLAG_ALLARGS	0x02	/* treat non-options as args to option "-1" */
+#define FLAG_LONGONLY	0x04	/* operate as getopt_long_only */
+
+/* return values */
+#define	BADCH		(int)'?'
+#define	BADARG		((*options == ':') ? (int)':' : (int)'?')
+#define	INORDER 	(int)1
+
+#ifndef __CYGWIN__
+#define __progname __argv[0]
+#else
+extern char __declspec(dllimport) *__progname;
+#endif
+
+#ifdef __CYGWIN__
+static char EMSG[] = "";
+#else
+#define	EMSG		""
+#endif
+
+static int getopt_internal(int, char * const *, const char *,
+			   const struct option *, int *, int);
+static int parse_long_options(char * const *, const char *,
+			      const struct option *, int *, int);
+static int gcd(int, int);
+static void permute_args(int, int, int, char * const *);
+
+static char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1;   /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+static void
+_vwarnx(const char *fmt,va_list ap)
+{
+  (void)fprintf(stderr,"%s: ",__progname);
+  if (fmt != NULL)
+    (void)vfprintf(stderr,fmt,ap);
+  (void)fprintf(stderr,"\n");
+}
+
+static void
+warnx(const char *fmt,...)
+{
+  va_list ap;
+  va_start(ap,fmt);
+  _vwarnx(fmt,ap);
+  va_end(ap);
+}
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(int a, int b)
+{
+	int c;
+
+	c = a % b;
+	while (c != 0) {
+		a = b;
+		b = c;
+		c = a % b;
+	}
+
+	return (b);
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(int panonopt_start, int panonopt_end, int opt_end,
+	char * const *nargv)
+{
+	int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+	char *swap;
+
+	/*
+	 * compute lengths of blocks and number and size of cycles
+	 */
+	nnonopts = panonopt_end - panonopt_start;
+	nopts = opt_end - panonopt_end;
+	ncycle = gcd(nnonopts, nopts);
+	cyclelen = (opt_end - panonopt_start) / ncycle;
+
+	for (i = 0; i < ncycle; i++) {
+		cstart = panonopt_end+i;
+		pos = cstart;
+		for (j = 0; j < cyclelen; j++) {
+			if (pos >= panonopt_end)
+				pos -= nnonopts;
+			else
+				pos += nopts;
+			swap = nargv[pos];
+			/* LINTED const cast */
+			((char **) nargv)[pos] = nargv[cstart];
+			/* LINTED const cast */
+			((char **)nargv)[cstart] = swap;
+		}
+	}
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ *	Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the BSD getopt]
+ */
+int
+getopt(int nargc, char * const *nargv, const char *options)
+{
+
+	/*
+	 * We don't pass FLAG_PERMUTE to getopt_internal() since
+	 * the BSD getopt(3) (unlike GNU) has never done this.
+	 *
+	 * Furthermore, since many privileged programs call getopt()
+	 * before dropping privileges it makes sense to keep things
+	 * as simple (and bug-free) as possible.
+	 */
+	return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
+}
+#endif /* REPLACE_GETOPT */
+
+//extern int getopt(int nargc, char * const *nargv, const char *options);
+
+#ifdef _BSD_SOURCE
+/*
+ * BSD adds the non-standard `optreset' feature, for reinitialisation
+ * of `getopt' parsing.  We support this feature, for applications which
+ * proclaim their BSD heritage, before including this header; however,
+ * to maintain portability, developers are advised to avoid it.
+ */
+# define optreset  __mingw_optreset
+extern int optreset;
+#endif
+#ifdef __cplusplus
+}
+#endif
+/*
+ * POSIX requires the `getopt' API to be specified in `unistd.h';
+ * thus, `unistd.h' includes this header.  However, we do not want
+ * to expose the `getopt_long' or `getopt_long_only' APIs, when
+ * included in this manner.  Thus, close the standard __GETOPT_H__
+ * declarations block, and open an additional __GETOPT_LONG_H__
+ * specific block, only when *not* __UNISTD_H_SOURCED__, in which
+ * to declare the extended API.
+ */
+#endif /* !defined(__GETOPT_H__) */
+
+#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
+#define __GETOPT_LONG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct option		/* specification for a long form option...	*/
+{
+  const char *name;		/* option name, without leading hyphens */
+  int         has_arg;		/* does it take an argument?		*/
+  int        *flag;		/* where to save its status, or NULL	*/
+  int         val;		/* its associated status value		*/
+};
+
+enum    		/* permitted values for its `has_arg' field...	*/
+{
+  no_argument = 0,      	/* option never takes an argument	*/
+  required_argument,		/* option always requires an argument	*/
+  optional_argument		/* option may take an argument		*/
+};
+
+/*
+ * parse_long_options --
+ *	Parse long options in argc/argv argument vector.
+ * Returns -1 if short_too is set and the option does not match long_options.
+ */
+static int
+parse_long_options(char * const *nargv, const char *options,
+	const struct option *long_options, int *idx, int short_too)
+{
+	char *current_argv, *has_equal;
+	size_t current_argv_len;
+	int i, ambiguous, match;
+
+#define IDENTICAL_INTERPRETATION(_x, _y)                                \
+	(long_options[(_x)].has_arg == long_options[(_y)].has_arg &&    \
+	 long_options[(_x)].flag == long_options[(_y)].flag &&          \
+	 long_options[(_x)].val == long_options[(_y)].val)
+
+	current_argv = place;
+	match = -1;
+	ambiguous = 0;
+
+	optind++;
+
+	if ((has_equal = strchr(current_argv, '=')) != NULL) {
+		/* argument found (--option=arg) */
+		current_argv_len = has_equal - current_argv;
+		has_equal++;
+	} else
+		current_argv_len = strlen(current_argv);
+
+	for (i = 0; long_options[i].name; i++) {
+		/* find matching long option */
+		if (strncmp(current_argv, long_options[i].name,
+		    current_argv_len))
+			continue;
+
+		if (strlen(long_options[i].name) == current_argv_len) {
+			/* exact match */
+			match = i;
+			ambiguous = 0;
+			break;
+		}
+		/*
+		 * If this is a known short option, don't allow
+		 * a partial match of a single character.
+		 */
+		if (short_too && current_argv_len == 1)
+			continue;
+
+		if (match == -1)	/* partial match */
+			match = i;
+		else if (!IDENTICAL_INTERPRETATION(i, match))
+			ambiguous = 1;
+	}
+	if (ambiguous) {
+		/* ambiguous abbreviation */
+		if (PRINT_ERROR)
+			warnx(ambig, (int)current_argv_len,
+			     current_argv);
+		optopt = 0;
+		return (BADCH);
+	}
+	if (match != -1) {		/* option found */
+		if (long_options[match].has_arg == no_argument
+		    && has_equal) {
+			if (PRINT_ERROR)
+				warnx(noarg, (int)current_argv_len,
+				     current_argv);
+			/*
+			 * XXX: GNU sets optopt to val regardless of flag
+			 */
+			if (long_options[match].flag == NULL)
+				optopt = long_options[match].val;
+			else
+				optopt = 0;
+			return (BADARG);
+		}
+		if (long_options[match].has_arg == required_argument ||
+		    long_options[match].has_arg == optional_argument) {
+			if (has_equal)
+				optarg = has_equal;
+			else if (long_options[match].has_arg ==
+			    required_argument) {
+				/*
+				 * optional argument doesn't use next nargv
+				 */
+				optarg = nargv[optind++];
+			}
+		}
+		if ((long_options[match].has_arg == required_argument)
+		    && (optarg == NULL)) {
+			/*
+			 * Missing argument; leading ':' indicates no error
+			 * should be generated.
+			 */
+			if (PRINT_ERROR)
+				warnx(recargstring,
+				    current_argv);
+			/*
+			 * XXX: GNU sets optopt to val regardless of flag
+			 */
+			if (long_options[match].flag == NULL)
+				optopt = long_options[match].val;
+			else
+				optopt = 0;
+			--optind;
+			return (BADARG);
+		}
+	} else {			/* unknown option */
+		if (short_too) {
+			--optind;
+			return (-1);
+		}
+		if (PRINT_ERROR)
+			warnx(illoptstring, current_argv);
+		optopt = 0;
+		return (BADCH);
+	}
+	if (idx)
+		*idx = match;
+	if (long_options[match].flag) {
+		*long_options[match].flag = long_options[match].val;
+		return (0);
+	} else
+		return (long_options[match].val);
+#undef IDENTICAL_INTERPRETATION
+}
+
+/*
+ * getopt_internal --
+ *	Parse argc/argv argument vector.  Called by user level routines.
+ */
+static int
+getopt_internal(int nargc, char * const *nargv, const char *options,
+	const struct option *long_options, int *idx, int flags)
+{
+	char *oli;				/* option letter list index */
+	int optchar, short_too;
+	static int posixly_correct = -1;
+
+	if (options == NULL)
+		return (-1);
+
+	/*
+	 * XXX Some GNU programs (like cvs) set optind to 0 instead of
+	 * XXX using optreset.  Work around this braindamage.
+	 */
+	if (optind == 0)
+		optind = optreset = 1;
+
+	/*
+	 * Disable GNU extensions if POSIXLY_CORRECT is set or options
+	 * string begins with a '+'.
+	 *
+	 * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or
+	 *                 optreset != 0 for GNU compatibility.
+	 */
+	if (posixly_correct == -1 || optreset != 0)
+		posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+	if (*options == '-')
+		flags |= FLAG_ALLARGS;
+	else if (posixly_correct || *options == '+')
+		flags &= ~FLAG_PERMUTE;
+	if (*options == '+' || *options == '-')
+		options++;
+
+	optarg = NULL;
+	if (optreset)
+		nonopt_start = nonopt_end = -1;
+start:
+	if (optreset || !*place) {		/* update scanning pointer */
+		optreset = 0;
+		if (optind >= nargc) {          /* end of argument vector */
+			place = EMSG;
+			if (nonopt_end != -1) {
+				/* do permutation, if we have to */
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			else if (nonopt_start != -1) {
+				/*
+				 * If we skipped non-options, set optind
+				 * to the first of them.
+				 */
+				optind = nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return (-1);
+		}
+		if (*(place = nargv[optind]) != '-' ||
+		    (place[1] == '\0' && strchr(options, '-') == NULL)) {
+			place = EMSG;		/* found non-option */
+			if (flags & FLAG_ALLARGS) {
+				/*
+				 * GNU extension:
+				 * return non-option as argument to option 1
+				 */
+				optarg = nargv[optind++];
+				return (INORDER);
+			}
+			if (!(flags & FLAG_PERMUTE)) {
+				/*
+				 * If no permutation wanted, stop parsing
+				 * at first non-option.
+				 */
+				return (-1);
+			}
+			/* do permutation */
+			if (nonopt_start == -1)
+				nonopt_start = optind;
+			else if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				nonopt_start = optind -
+				    (nonopt_end - nonopt_start);
+				nonopt_end = -1;
+			}
+			optind++;
+			/* process next argument */
+			goto start;
+		}
+		if (nonopt_start != -1 && nonopt_end == -1)
+			nonopt_end = optind;
+
+		/*
+		 * If we have "-" do nothing, if "--" we are done.
+		 */
+		if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
+			optind++;
+			place = EMSG;
+			/*
+			 * We found an option (--), so if we skipped
+			 * non-options, we have to permute.
+			 */
+			if (nonopt_end != -1) {
+				permute_args(nonopt_start, nonopt_end,
+				    optind, nargv);
+				optind -= nonopt_end - nonopt_start;
+			}
+			nonopt_start = nonopt_end = -1;
+			return (-1);
+		}
+	}
+
+	/*
+	 * Check long options if:
+	 *  1) we were passed some
+	 *  2) the arg is not just "-"
+	 *  3) either the arg starts with -- we are getopt_long_only()
+	 */
+	if (long_options != NULL && place != nargv[optind] &&
+	    (*place == '-' || (flags & FLAG_LONGONLY))) {
+		short_too = 0;
+		if (*place == '-')
+			place++;		/* --foo long option */
+		else if (*place != ':' && strchr(options, *place) != NULL)
+			short_too = 1;		/* could be short option too */
+
+		optchar = parse_long_options(nargv, options, long_options,
+		    idx, short_too);
+		if (optchar != -1) {
+			place = EMSG;
+			return (optchar);
+		}
+	}
+
+	if ((optchar = (int)*place++) == (int)':' ||
+	    (optchar == (int)'-' && *place != '\0') ||
+	    (oli = (char*)strchr(options, optchar)) == NULL) {
+		/*
+		 * If the user specified "-" and  '-' isn't listed in
+		 * options, return -1 (non-option) as per POSIX.
+		 * Otherwise, it is an unknown option character (or ':').
+		 */
+		if (optchar == (int)'-' && *place == '\0')
+			return (-1);
+		if (!*place)
+			++optind;
+		if (PRINT_ERROR)
+			warnx(illoptchar, optchar);
+		optopt = optchar;
+		return (BADCH);
+	}
+	if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
+		/* -W long-option */
+		if (*place)			/* no space */
+			/* NOTHING */;
+		else if (++optind >= nargc) {	/* no arg */
+			place = EMSG;
+			if (PRINT_ERROR)
+				warnx(recargchar, optchar);
+			optopt = optchar;
+			return (BADARG);
+		} else				/* white space */
+			place = nargv[optind];
+		optchar = parse_long_options(nargv, options, long_options,
+		    idx, 0);
+		place = EMSG;
+		return (optchar);
+	}
+	if (*++oli != ':') {			/* doesn't take argument */
+		if (!*place)
+			++optind;
+	} else {				/* takes (optional) argument */
+		optarg = NULL;
+		if (*place)			/* no white space */
+			optarg = place;
+		else if (oli[1] != ':') {	/* arg not optional */
+			if (++optind >= nargc) {	/* no arg */
+				place = EMSG;
+				if (PRINT_ERROR)
+					warnx(recargchar, optchar);
+				optopt = optchar;
+				return (BADARG);
+			} else
+				optarg = nargv[optind];
+		}
+		place = EMSG;
+		++optind;
+	}
+	/* dump back option letter */
+	return (optchar);
+}
+
+/*
+ * getopt_long --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx)
+{
+
+	return (getopt_internal(nargc, nargv, options, long_options, idx,
+	    FLAG_PERMUTE));
+}
+
+/*
+ * getopt_long_only --
+ *	Parse argc/argv argument vector.
+ */
+int
+getopt_long_only(int nargc, char * const *nargv, const char *options,
+    const struct option *long_options, int *idx)
+{
+
+	return (getopt_internal(nargc, nargv, options, long_options, idx,
+	    FLAG_PERMUTE|FLAG_LONGONLY));
+}
+
+//extern int getopt_long(int nargc, char * const *nargv, const char *options,
+//    const struct option *long_options, int *idx);
+//extern int getopt_long_only(int nargc, char * const *nargv, const char *options,
+//    const struct option *long_options, int *idx);
+/*
+ * Previous MinGW implementation had...
+ */
+#ifndef HAVE_DECL_GETOPT
+/*
+ * ...for the long form API only; keep this for compatibility.
+ */
+# define HAVE_DECL_GETOPT	1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
diff --git a/compat/jansson/CMakeLists.txt b/src/3rdparty/jansson/CMakeLists.txt
similarity index 91%
rename from compat/jansson/CMakeLists.txt
rename to src/3rdparty/jansson/CMakeLists.txt
index 9a73da225..7bd74c671 100644
--- a/compat/jansson/CMakeLists.txt
+++ b/src/3rdparty/jansson/CMakeLists.txt
@@ -6,6 +6,8 @@ add_definitions(-DHAVE_CONFIG_H)
 # Add the lib sources.
 file(GLOB JANSSON_SRC *.c)
 
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os")
+
 set(JANSSON_HDR_PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/hashtable.h
    ${CMAKE_CURRENT_SOURCE_DIR}/jansson_private.h
diff --git a/compat/jansson/LICENSE b/src/3rdparty/jansson/LICENSE
similarity index 100%
rename from compat/jansson/LICENSE
rename to src/3rdparty/jansson/LICENSE
diff --git a/compat/jansson/dump.c b/src/3rdparty/jansson/dump.c
similarity index 89%
rename from compat/jansson/dump.c
rename to src/3rdparty/jansson/dump.c
index 6b1aabd45..a23fabb7c 100644
--- a/compat/jansson/dump.c
+++ b/src/3rdparty/jansson/dump.c
@@ -9,13 +9,17 @@
 #define _GNU_SOURCE
 #endif
 
+#include "jansson_private.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
 #include "jansson.h"
-#include "jansson_private.h"
 #include "strbuffer.h"
 #include "utf.h"
 
@@ -25,11 +29,28 @@
 #define FLAGS_TO_INDENT(f)      ((f) & 0x1F)
 #define FLAGS_TO_PRECISION(f)   (((f) >> 11) & 0x1F)
 
+struct buffer {
+    const size_t size;
+    size_t used;
+    char *data;
+};
+
 static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
 {
     return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
 }
 
+static int dump_to_buffer(const char *buffer, size_t size, void *data)
+{
+    struct buffer *buf = (struct buffer *)data;
+
+    if(buf->used + size <= buf->size)
+        memcpy(&buf->data[buf->used], buffer, size);
+
+    buf->used += size;
+    return 0;
+}
+
 static int dump_to_file(const char *buffer, size_t size, void *data)
 {
     FILE *dest = (FILE *)data;
@@ -38,6 +59,16 @@ static int dump_to_file(const char *buffer, size_t size, void *data)
     return 0;
 }
 
+static int dump_to_fd(const char *buffer, size_t size, void *data)
+{
+    int *dest = (int *)data;
+#ifdef HAVE_UNISTD_H
+    if(write(*dest, buffer, size) == (ssize_t)size)
+        return 0;
+#endif
+    return -1;
+}
+
 /* 32 spaces (the maximum indentation size) */
 static const char whitespace[] = "                                ";
 
@@ -168,6 +199,10 @@ static int compare_keys(const void *key1, const void *key2)
 static int do_dump(const json_t *json, size_t flags, int depth,
                    json_dump_callback_t dump, void *data)
 {
+    int embed = flags & JSON_EMBED;
+
+    flags &= ~JSON_EMBED;
+
     if(!json)
         return -1;
 
@@ -227,11 +262,11 @@ static int do_dump(const json_t *json, size_t flags, int depth,
 
             n = json_array_size(json);
 
-            if(dump("[", 1, data))
+            if(!embed && dump("[", 1, data))
                 goto array_error;
             if(n == 0) {
                 array->visited = 0;
-                return dump("]", 1, data);
+                return embed ? 0 : dump("]", 1, data);
             }
             if(dump_indent(flags, depth + 1, 0, dump, data))
                 goto array_error;
@@ -255,7 +290,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
             }
 
             array->visited = 0;
-            return dump("]", 1, data);
+            return embed ? 0 : dump("]", 1, data);
 
         array_error:
             array->visited = 0;
@@ -286,11 +321,11 @@ static int do_dump(const json_t *json, size_t flags, int depth,
 
             iter = json_object_iter((json_t *)json);
 
-            if(dump("{", 1, data))
+            if(!embed && dump("{", 1, data))
                 goto object_error;
             if(!iter) {
                 object->visited = 0;
-                return dump("}", 1, data);
+                return embed ? 0 : dump("}", 1, data);
             }
             if(dump_indent(flags, depth + 1, 0, dump, data))
                 goto object_error;
@@ -386,7 +421,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
             }
 
             object->visited = 0;
-            return dump("}", 1, data);
+            return embed ? 0 : dump("}", 1, data);
 
         object_error:
             object->visited = 0;
@@ -416,11 +451,26 @@ char *json_dumps(const json_t *json, size_t flags)
     return result;
 }
 
+size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags)
+{
+    struct buffer buf = { size, 0, buffer };
+
+    if(json_dump_callback(json, dump_to_buffer, (void *)&buf, flags))
+        return 0;
+
+    return buf.used;
+}
+
 int json_dumpf(const json_t *json, FILE *output, size_t flags)
 {
     return json_dump_callback(json, dump_to_file, (void *)output, flags);
 }
 
+int json_dumpfd(const json_t *json, int output, size_t flags)
+{
+    return json_dump_callback(json, dump_to_fd, (void *)&output, flags);
+}
+
 int json_dump_file(const json_t *json, const char *path, size_t flags)
 {
     int result;
diff --git a/compat/jansson/error.c b/src/3rdparty/jansson/error.c
similarity index 100%
rename from compat/jansson/error.c
rename to src/3rdparty/jansson/error.c
diff --git a/compat/jansson/hashtable.c b/src/3rdparty/jansson/hashtable.c
similarity index 100%
rename from compat/jansson/hashtable.c
rename to src/3rdparty/jansson/hashtable.c
diff --git a/compat/jansson/hashtable.h b/src/3rdparty/jansson/hashtable.h
similarity index 100%
rename from compat/jansson/hashtable.h
rename to src/3rdparty/jansson/hashtable.h
diff --git a/compat/jansson/hashtable_seed.c b/src/3rdparty/jansson/hashtable_seed.c
similarity index 98%
rename from compat/jansson/hashtable_seed.c
rename to src/3rdparty/jansson/hashtable_seed.c
index 751e0e326..8aed54068 100644
--- a/compat/jansson/hashtable_seed.c
+++ b/src/3rdparty/jansson/hashtable_seed.c
@@ -168,12 +168,12 @@ static uint32_t generate_seed() {
     int done = 0;
 
 #if !defined(_WIN32) && defined(USE_URANDOM)
-    if (!done && seed_from_urandom(&seed) == 0)
+    if (seed_from_urandom(&seed) == 0)
         done = 1;
 #endif
 
 #if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
-    if (!done && seed_from_windows_cryptoapi(&seed) == 0)
+    if (seed_from_windows_cryptoapi(&seed) == 0)
         done = 1;
 #endif
 
diff --git a/compat/jansson/jansson.h b/src/3rdparty/jansson/jansson.h
similarity index 96%
rename from compat/jansson/jansson.h
rename to src/3rdparty/jansson/jansson.h
index 591f2a944..a5927bd63 100644
--- a/compat/jansson/jansson.h
+++ b/src/3rdparty/jansson/jansson.h
@@ -21,11 +21,11 @@ extern "C" {
 /* version */
 
 #define JANSSON_MAJOR_VERSION  2
-#define JANSSON_MINOR_VERSION  9
+#define JANSSON_MINOR_VERSION  10
 #define JANSSON_MICRO_VERSION  0
 
 /* Micro version is omitted if it's 0 */
-#define JANSSON_VERSION  "2.9"
+#define JANSSON_VERSION  "2.10"
 
 /* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
    for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
@@ -273,6 +273,7 @@ typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
 json_t *json_loads(const char *input, size_t flags, json_error_t *error);
 json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
 json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
+json_t *json_loadfd(int input, size_t flags, json_error_t *error);
 json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
 json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error);
 
@@ -288,11 +289,14 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
 #define JSON_ENCODE_ANY         0x200
 #define JSON_ESCAPE_SLASH       0x400
 #define JSON_REAL_PRECISION(n)  (((n) & 0x1F) << 11)
+#define JSON_EMBED              0x10000
 
 typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
 
 char *json_dumps(const json_t *json, size_t flags);
+size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags);
 int json_dumpf(const json_t *json, FILE *output, size_t flags);
+int json_dumpfd(const json_t *json, int output, size_t flags);
 int json_dump_file(const json_t *json, const char *path, size_t flags);
 int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags);
 
diff --git a/compat/jansson/jansson_config.h b/src/3rdparty/jansson/jansson_config.h
similarity index 100%
rename from compat/jansson/jansson_config.h
rename to src/3rdparty/jansson/jansson_config.h
diff --git a/compat/jansson/jansson_private.h b/src/3rdparty/jansson/jansson_private.h
similarity index 98%
rename from compat/jansson/jansson_private.h
rename to src/3rdparty/jansson/jansson_private.h
index 4a4927bb2..5ed961582 100644
--- a/compat/jansson/jansson_private.h
+++ b/src/3rdparty/jansson/jansson_private.h
@@ -8,6 +8,7 @@
 #ifndef JANSSON_PRIVATE_H
 #define JANSSON_PRIVATE_H
 
+#include "jansson_private_config.h"
 #include <stddef.h>
 #include "jansson.h"
 #include "hashtable.h"
diff --git a/compat/jansson/jansson_private_config.h b/src/3rdparty/jansson/jansson_private_config.h
similarity index 92%
rename from compat/jansson/jansson_private_config.h
rename to src/3rdparty/jansson/jansson_private_config.h
index 2b17f182f..671993d95 100644
--- a/compat/jansson/jansson_private_config.h
+++ b/src/3rdparty/jansson/jansson_private_config.h
@@ -2,7 +2,9 @@
 /* jansson_private_config.h.in.  Generated from configure.ac by autoheader.  */
 
 /* Define to 1 if gcc's __atomic builtins are available */
-#define HAVE_ATOMIC_BUILTINS 1
+#ifndef _MSC_VER
+#   define HAVE_ATOMIC_BUILTINS 1
+#endif
 
 /* Define to 1 if you have the `close' function. */
 #define HAVE_CLOSE 1
@@ -20,7 +22,9 @@
 #define HAVE_GETPID 1
 
 /* Define to 1 if you have the `gettimeofday' function. */
-#define HAVE_GETTIMEOFDAY 1
+#ifndef _MSC_VER
+#   define HAVE_GETTIMEOFDAY 1
+#endif
 
 /* Define to 1 if you have the <inttypes.h> header file. */
 #define HAVE_INTTYPES_H 1
@@ -44,10 +48,14 @@
 #define HAVE_READ 1
 
 /* Define to 1 if you have the <sched.h> header file. */
-#define HAVE_SCHED_H 1
+#ifndef _MSC_VER
+#   define HAVE_SCHED_H 1
+#endif
 
 /* Define to 1 if you have the `sched_yield' function. */
-#define HAVE_SCHED_YIELD 1
+#ifndef _MSC_VER
+#   define HAVE_SCHED_YIELD 1
+#endif
 
 /* Define to 1 if you have the <stdint.h> header file. */
 #define HAVE_STDINT_H 1
@@ -68,19 +76,25 @@
 #define HAVE_SYNC_BUILTINS 1
 
 /* Define to 1 if you have the <sys/param.h> header file. */
-#define HAVE_SYS_PARAM_H 1
+#ifndef _MSC_VER
+#   define HAVE_SYS_PARAM_H 1
+#endif
 
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #define HAVE_SYS_STAT_H 1
 
 /* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
+#ifndef _MSC_VER
+#   define HAVE_SYS_TIME_H 1
+#endif
 
 /* Define to 1 if you have the <sys/types.h> header file. */
 #define HAVE_SYS_TYPES_H 1
 
 /* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
+#ifndef _MSC_VER
+#   define HAVE_UNISTD_H 1
+#endif
 
 /* Define to 1 if the system has the type 'unsigned long long int'. */
 #define HAVE_UNSIGNED_LONG_LONG_INT 1
diff --git a/compat/jansson/load.c b/src/3rdparty/jansson/load.c
similarity index 96%
rename from compat/jansson/load.c
rename to src/3rdparty/jansson/load.c
index 7a8f96ecb..c212489a1 100644
--- a/compat/jansson/load.c
+++ b/src/3rdparty/jansson/load.c
@@ -9,15 +9,19 @@
 #define _GNU_SOURCE
 #endif
 
+#include "jansson_private.h"
+
 #include <errno.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
 #include "jansson.h"
-#include "jansson_private.h"
 #include "strbuffer.h"
 #include "utf.h"
 
@@ -340,7 +344,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error)
             /* control character */
             lex_unget_unsave(lex, c);
             if(c == '\n')
-                error_set(error, lex, "unexpected newline", c);
+                error_set(error, lex, "unexpected newline");
             else
                 error_set(error, lex, "control character 0x%x", c);
             goto out;
@@ -914,7 +918,7 @@ static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error)
 typedef struct
 {
     const char *data;
-    int pos;
+    size_t pos;
 } string_data_t;
 
 static int string_get(void *data)
@@ -1028,6 +1032,45 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error)
     return result;
 }
 
+static int fd_get_func(int *fd)
+{
+    uint8_t c;
+#ifdef HAVE_UNISTD_H
+    if (read(*fd, &c, 1) == 1)
+        return c;
+#endif
+    return EOF;
+}
+
+json_t *json_loadfd(int input, size_t flags, json_error_t *error)
+{
+    lex_t lex;
+    const char *source;
+    json_t *result;
+
+#ifdef HAVE_UNISTD_H
+    if(input == STDIN_FILENO)
+        source = "<stdin>";
+    else
+#endif
+        source = "<stream>";
+
+    jsonp_error_init(error, source);
+
+    if (input < 0) {
+        error_set(error, NULL, "wrong arguments");
+        return NULL;
+    }
+
+    if(lex_init(&lex, (get_func)fd_get_func, flags, &input))
+        return NULL;
+
+    result = parse_json(&lex, flags, error);
+
+    lex_close(&lex);
+    return result;
+}
+
 json_t *json_load_file(const char *path, size_t flags, json_error_t *error)
 {
     json_t *result;
diff --git a/compat/jansson/lookup3.h b/src/3rdparty/jansson/lookup3.h
similarity index 100%
rename from compat/jansson/lookup3.h
rename to src/3rdparty/jansson/lookup3.h
diff --git a/compat/jansson/memory.c b/src/3rdparty/jansson/memory.c
similarity index 100%
rename from compat/jansson/memory.c
rename to src/3rdparty/jansson/memory.c
diff --git a/compat/jansson/pack_unpack.c b/src/3rdparty/jansson/pack_unpack.c
similarity index 100%
rename from compat/jansson/pack_unpack.c
rename to src/3rdparty/jansson/pack_unpack.c
diff --git a/compat/jansson/strbuffer.c b/src/3rdparty/jansson/strbuffer.c
similarity index 100%
rename from compat/jansson/strbuffer.c
rename to src/3rdparty/jansson/strbuffer.c
diff --git a/compat/jansson/strbuffer.h b/src/3rdparty/jansson/strbuffer.h
similarity index 100%
rename from compat/jansson/strbuffer.h
rename to src/3rdparty/jansson/strbuffer.h
diff --git a/compat/jansson/strconv.c b/src/3rdparty/jansson/strconv.c
similarity index 100%
rename from compat/jansson/strconv.c
rename to src/3rdparty/jansson/strconv.c
diff --git a/compat/jansson/utf.c b/src/3rdparty/jansson/utf.c
similarity index 100%
rename from compat/jansson/utf.c
rename to src/3rdparty/jansson/utf.c
diff --git a/compat/jansson/utf.h b/src/3rdparty/jansson/utf.h
similarity index 100%
rename from compat/jansson/utf.h
rename to src/3rdparty/jansson/utf.h
diff --git a/compat/jansson/value.c b/src/3rdparty/jansson/value.c
similarity index 100%
rename from compat/jansson/value.c
rename to src/3rdparty/jansson/value.c
diff --git a/compat/libcpuid/CMakeLists.txt b/src/3rdparty/libcpuid/CMakeLists.txt
similarity index 56%
rename from compat/libcpuid/CMakeLists.txt
rename to src/3rdparty/libcpuid/CMakeLists.txt
index 5c37492ab..51eab1d36 100644
--- a/compat/libcpuid/CMakeLists.txt
+++ b/src/3rdparty/libcpuid/CMakeLists.txt
@@ -3,17 +3,19 @@ project (cpuid C)
 
 add_definitions(/DVERSION="0.4.0")
 
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os")
+
 set(HEADERS
     libcpuid.h
     libcpuid_types.h
     libcpuid_constants.h
     libcpuid_internal.h
-amd_code_t.h
-intel_code_t.h
-recog_amd.h
-recog_intel.h
-asm-bits.h
-libcpuid_util.h
+    amd_code_t.h
+    intel_code_t.h
+    recog_amd.h
+    recog_intel.h
+    asm-bits.h
+    libcpuid_util.h
     )
 
 set(SOURCES
@@ -24,7 +26,13 @@ set(SOURCES
     libcpuid_util.c
    )
 
+if (CMAKE_CL_64)
+    enable_language(ASM_MASM)
+    set(SOURCES_ASM masm-x64.asm)
+endif()
+
 add_library(cpuid STATIC
     ${HEADERS}
     ${SOURCES}
+    ${SOURCES_ASM}
     )
diff --git a/compat/libcpuid/amd_code_t.h b/src/3rdparty/libcpuid/amd_code_t.h
similarity index 100%
rename from compat/libcpuid/amd_code_t.h
rename to src/3rdparty/libcpuid/amd_code_t.h
diff --git a/compat/libcpuid/asm-bits.c b/src/3rdparty/libcpuid/asm-bits.c
similarity index 100%
rename from compat/libcpuid/asm-bits.c
rename to src/3rdparty/libcpuid/asm-bits.c
diff --git a/compat/libcpuid/asm-bits.h b/src/3rdparty/libcpuid/asm-bits.h
similarity index 100%
rename from compat/libcpuid/asm-bits.h
rename to src/3rdparty/libcpuid/asm-bits.h
diff --git a/compat/libcpuid/cpuid_main.c b/src/3rdparty/libcpuid/cpuid_main.c
similarity index 82%
rename from compat/libcpuid/cpuid_main.c
rename to src/3rdparty/libcpuid/cpuid_main.c
index 64c4198b4..f22c7dd69 100644
--- a/compat/libcpuid/cpuid_main.c
+++ b/src/3rdparty/libcpuid/cpuid_main.c
@@ -46,11 +46,6 @@ int set_error(cpu_error_t err)
 	return (int) err;
 }
 
-static void raw_data_t_constructor(struct cpu_raw_data_t* raw)
-{
-	memset(raw, 0, sizeof(struct cpu_raw_data_t));
-}
-
 static void cpu_id_t_constructor(struct cpu_id_t* id)
 {
 	memset(id, 0, sizeof(struct cpu_id_t));
@@ -60,29 +55,6 @@ static void cpu_id_t_constructor(struct cpu_id_t* id)
 	id->sse_size = -1;
 }
 
-static int parse_token(const char* expected_token, const char *token,
-                        const char *value, uint32_t array[][4], int limit, int *recognized)
-{
-	char format[32];
-	int veax, vebx, vecx, vedx;
-	int index;
-
-	if (*recognized) return 1; /* already recognized */
-	if (strncmp(token, expected_token, strlen(expected_token))) return 1; /* not what we search for */
-	sprintf(format, "%s[%%d]", expected_token);
-	*recognized = 1;
-	if (1 == sscanf(token, format, &index) && index >=0 && index < limit) {
-		if (4 == sscanf(value, "%x%x%x%x", &veax, &vebx, &vecx, &vedx)) {
-			array[index][0] = veax;
-			array[index][1] = vebx;
-			array[index][2] = vecx;
-			array[index][3] = vedx;
-			return 1;
-		}
-	}
-	return 0;
-}
-
 /* get_total_cpus() system specific code: uses OS routines to determine total number of CPUs */
 #ifdef __APPLE__
 #include <unistd.h>
@@ -117,7 +89,7 @@ static int get_total_cpus(void)
 #if defined linux || defined __linux__ || defined __sun
 #include <sys/sysinfo.h>
 #include <unistd.h>
-
+ 
 static int get_total_cpus(void)
 {
 	return sysconf(_SC_NPROCESSORS_ONLN);
@@ -249,42 +221,42 @@ static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* da
 
 static cpu_vendor_t cpuid_vendor_identify(const uint32_t *raw_vendor, char *vendor_str)
 {
-	int i;
-	cpu_vendor_t vendor = VENDOR_UNKNOWN;
-	const struct { cpu_vendor_t vendor; char match[16]; }
-	matchtable[NUM_CPU_VENDORS] = {
-		/* source: http://www.sandpile.org/ia32/cpuid.htm */
-		{ VENDOR_INTEL		, "GenuineIntel" },
-		{ VENDOR_AMD		, "AuthenticAMD" },
-		{ VENDOR_CYRIX		, "CyrixInstead" },
-		{ VENDOR_NEXGEN		, "NexGenDriven" },
-		{ VENDOR_TRANSMETA	, "GenuineTMx86" },
-		{ VENDOR_UMC		, "UMC UMC UMC " },
-		{ VENDOR_CENTAUR	, "CentaurHauls" },
-		{ VENDOR_RISE		, "RiseRiseRise" },
-		{ VENDOR_SIS		, "SiS SiS SiS " },
-		{ VENDOR_NSC		, "Geode by NSC" },
-	};
+    int i;
+    cpu_vendor_t vendor = VENDOR_UNKNOWN;
+    const struct { cpu_vendor_t vendor; char match[16]; }
+    matchtable[NUM_CPU_VENDORS] = {
+        /* source: http://www.sandpile.org/ia32/cpuid.htm */
+        { VENDOR_INTEL		, "GenuineIntel" },
+        { VENDOR_AMD		, "AuthenticAMD" },
+        { VENDOR_CYRIX		, "CyrixInstead" },
+        { VENDOR_NEXGEN		, "NexGenDriven" },
+        { VENDOR_TRANSMETA	, "GenuineTMx86" },
+        { VENDOR_UMC		, "UMC UMC UMC " },
+        { VENDOR_CENTAUR	, "CentaurHauls" },
+        { VENDOR_RISE		, "RiseRiseRise" },
+        { VENDOR_SIS		, "SiS SiS SiS " },
+        { VENDOR_NSC		, "Geode by NSC" },
+    };
 
-	memcpy(vendor_str + 0, &raw_vendor[1], 4);
-	memcpy(vendor_str + 4, &raw_vendor[3], 4);
-	memcpy(vendor_str + 8, &raw_vendor[2], 4);
-	vendor_str[12] = 0;
+    memcpy(vendor_str + 0, &raw_vendor[1], 4);
+    memcpy(vendor_str + 4, &raw_vendor[3], 4);
+    memcpy(vendor_str + 8, &raw_vendor[2], 4);
+    vendor_str[12] = 0;
 
-	/* Determine vendor: */
-	for (i = 0; i < NUM_CPU_VENDORS; i++)
-		if (!strcmp(vendor_str, matchtable[i].match)) {
-			vendor = matchtable[i].vendor;
-			break;
-		}
-	return vendor;
+    /* Determine vendor: */
+    for (i = 0; i < NUM_CPU_VENDORS; i++)
+        if (!strcmp(vendor_str, matchtable[i].match)) {
+            vendor = matchtable[i].vendor;
+            break;
+        }
+    return vendor;
 }
 
 static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
 {
 	int i, j, basic, xmodel, xfamily, ext;
 	char brandstr[64] = {0};
-	data->vendor = cpuid_vendor_identify(raw->basic_cpuid[0], data->vendor_str);
+    data->vendor = cpuid_vendor_identify(raw->basic_cpuid[0], data->vendor_str);
 
 	if (data->vendor == VENDOR_UNKNOWN)
 		return set_error(ERR_CPU_UNKN);
@@ -302,7 +274,7 @@ static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* dat
 		data->ext_model = data->model + (xmodel << 4);
 	}
 	ext = raw->ext_cpuid[0][0] - 0x8000000;
-
+	
 	/* obtain the brand string, if present: */
 	if (ext >= 4) {
 		for (i = 0; i < 3; i++)
@@ -320,27 +292,6 @@ static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* dat
 	return set_error(ERR_OK);
 }
 
-static void make_list_from_string(const char* csv, struct cpu_list_t* list)
-{
-	int i, n, l, last;
-	l = (int) strlen(csv);
-	n = 0;
-	for (i = 0; i < l; i++) if (csv[i] == ',') n++;
-	n++;
-	list->num_entries = n;
-	list->names = (char**) malloc(sizeof(char*) * n);
-	last = -1;
-	n = 0;
-	for (i = 0; i <= l; i++) if (i == l || csv[i] == ',') {
-		list->names[n] = (char*) malloc(i - last);
-		memcpy(list->names[n], &csv[last + 1], i - last - 1);
-		list->names[n][i - last - 1] = '\0';
-		n++;
-		last = i;
-	}
-}
-
-
 /* Interface: */
 
 int cpuid_get_total_cpus(void)
diff --git a/compat/libcpuid/intel_code_t.h b/src/3rdparty/libcpuid/intel_code_t.h
similarity index 100%
rename from compat/libcpuid/intel_code_t.h
rename to src/3rdparty/libcpuid/intel_code_t.h
diff --git a/compat/libcpuid/libcpuid.h b/src/3rdparty/libcpuid/libcpuid.h
similarity index 56%
rename from compat/libcpuid/libcpuid.h
rename to src/3rdparty/libcpuid/libcpuid.h
index f99c0fe55..c44990c31 100644
--- a/compat/libcpuid/libcpuid.h
+++ b/src/3rdparty/libcpuid/libcpuid.h
@@ -610,39 +610,6 @@ void cpu_exec_cpuid_ext(uint32_t* regs);
  */
 int cpuid_get_raw_data(struct cpu_raw_data_t* data);
 
-/**
- * @brief Writes the raw CPUID data to a text file
- * @param data - a pointer to cpu_raw_data_t structure
- * @param filename - the path of the file, where the serialized data should be
- *                   written. If empty, stdout will be used.
- * @note This is intended primarily for debugging. On some processor, which is
- *       not currently supported or not completely recognized by cpu_identify,
- *       one can still successfully get the raw data and write it to a file.
- *       libcpuid developers can later import this file and debug the detection
- *       code as if running on the actual hardware.
- *       The file is simple text format of "something=value" pairs. Version info
- *       is also written, but the format is not intended to be neither backward-
- *       nor forward compatible.
- * @returns zero if successful, and some negative number on error.
- *          The error message can be obtained by calling \ref cpuid_error.
- *          @see cpu_error_t
- */
-int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
-
-/**
- * @brief Reads raw CPUID data from file
- * @param data - a pointer to cpu_raw_data_t structure. The deserialized data will
- *               be written here.
- * @param filename - the path of the file, containing the serialized raw data.
- *                   If empty, stdin will be used.
- * @note This function may fail, if the file is created by different version of
- *       the library. Also, see the notes on cpuid_serialize_raw_data.
- * @returns zero if successful, and some negative number on error.
- *          The error message can be obtained by calling \ref cpuid_error.
- *          @see cpu_error_t
-*/
-int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
-
 /**
  * @brief Identifies the CPU
  * @param raw - Input - a pointer to the raw CPUID data, which is obtained
@@ -668,222 +635,6 @@ int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename
  */
 int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data);
 
-/**
- * @brief Returns the short textual representation of a CPU flag
- * @param feature - the feature, whose textual representation is wanted.
- * @returns a constant string like "fpu", "tsc", "sse2", etc.
- * @note the names of the returned flags are compatible with those from
- *       /proc/cpuinfo in Linux, with the exception of `tm_amd'
- */
-const char* cpu_feature_str(cpu_feature_t feature);
-
-/**
- * @brief Returns textual description of the last error
- *
- * libcpuid stores an `errno'-style error status, whose description
- * can be obtained with this function.
- * @note This function is not thread-safe
- * @see cpu_error_t
- */
-const char* cpuid_error(void);
-
-/**
- * @brief Executes RDTSC
- *
- * The RDTSC (ReaD Time Stamp Counter) instruction gives access to an
- * internal 64-bit counter, which usually increments at each clock cycle.
- * This can be used for various timing routines, and as a very precise
- * clock source. It is set to zero on system startup. Beware that may not
- * increment at the same frequency as the CPU. Consecutive calls of RDTSC
- * are, however, guaranteed to return monotonically-increasing values.
- *
- * @param result - a pointer to a 64-bit unsigned integer, where the TSC value
- *                 will be stored
- *
- * @note  If 100% compatibility is a concern, you must first check if the
- * RDTSC instruction is present (if it is not, your program will crash
- * with "invalid opcode" exception). Only some very old processors (i486,
- * early AMD K5 and some Cyrix CPUs) lack that instruction - they should
- * have become exceedingly rare these days. To verify RDTSC presence,
- * run cpu_identify() and check flags[CPU_FEATURE_TSC].
- *
- * @note The monotonically increasing nature of the TSC may be violated
- * on SMP systems, if their TSC clocks run at different rate. If the OS
- * doesn't account for that, the TSC drift may become arbitrary large.
- */
-void cpu_rdtsc(uint64_t* result);
-
-/**
- * @brief Store TSC and timing info
- *
- * This function stores the current TSC value and current
- * time info from a precise OS-specific clock source in the cpu_mark_t
- * structure. The sys_clock field contains time with microsecond resolution.
- * The values can later be used to measure time intervals, number of clocks,
- * FPU frequency, etc.
- * @see cpu_rdtsc
- *
- * @param mark [out] - a pointer to a cpu_mark_t structure
- */
-void cpu_tsc_mark(struct cpu_mark_t* mark);
-
-/**
- * @brief Calculate TSC and timing difference
- *
- * @param mark - input/output: a pointer to a cpu_mark_t sturcture, which has
- *               already been initialized by cpu_tsc_mark. The difference in
- *               TSC and time will be written here.
- *
- * This function calculates the TSC and time difference, by obtaining the
- * current TSC and timing values and subtracting the contents of the `mark'
- * structure from them. Results are written in the same structure.
- *
- * Example:
- * @code
- * ...
- * struct cpu_mark_t mark;
- * cpu_tsc_mark(&mark);
- * foo();
- * cpu_tsc_unmark(&mark);
- * printf("Foo finished. Executed in %llu cycles and %llu usecs\n",
- *        mark.tsc, mark.sys_clock);
- * ...
- * @endcode
- */
-void cpu_tsc_unmark(struct cpu_mark_t* mark);
-
-/**
- * @brief Calculates the CPU clock
- *
- * @param mark - pointer to a cpu_mark_t structure, which has been initialized
- *   with cpu_tsc_mark and later `stopped' with cpu_tsc_unmark.
- *
- * @note For reliable results, the marked time interval should be at least about
- * 10 ms.
- *
- * @returns the CPU clock frequency, in MHz. Due to measurement error, it will
- * differ from the true value in a few least-significant bits. Accuracy depends
- * on the timing interval - the more, the better. If the timing interval is
- * insufficient, the result is -1. Also, see the comment on cpu_clock_measure
- * for additional issues and pitfalls in using RDTSC for CPU frequency
- * measurements.
- */
-int cpu_clock_by_mark(struct cpu_mark_t* mark);
-
-/**
- * @brief Returns the CPU clock, as reported by the OS
- *
- * This function uses OS-specific functions to obtain the CPU clock. It may
- * differ from the true clock for several reasons:<br><br>
- *
- * i) The CPU might be in some power saving state, while the OS reports its
- *    full-power frequency, or vice-versa.<br>
- * ii) In some cases you can raise or lower the CPU frequency with overclocking
- *     utilities and the OS will not notice.
- *
- * @returns the CPU clock frequency in MHz. If the OS is not (yet) supported
- * or lacks the necessary reporting machinery, the return value is -1
- */
-int cpu_clock_by_os(void);
-
-/**
- * @brief Measure the CPU clock frequency
- *
- * @param millis - How much time to waste in the busy-wait cycle. In millisecs.
- *                 Useful values 10 - 1000
- * @param quad_check - Do a more thorough measurement if nonzero
- *                     (see the explanation).
- *
- * The function performs a busy-wait cycle for the given time and calculates
- * the CPU frequency by the difference of the TSC values. The accuracy of the
- * calculation depends on the length of the busy-wait cycle: more is better,
- * but 100ms should be enough for most purposes.
- *
- * While this will calculate the CPU frequency correctly in most cases, there are
- * several reasons why it might be incorrect:<br>
- *
- * i) RDTSC doesn't guarantee it will run at the same clock as the CPU.
- *    Apparently there aren't CPUs at the moment, but still, there's no
- *    guarantee.<br>
- * ii) The CPU might be in a low-frequency power saving mode, and the CPU
- *     might be switched to higher frequency at any time. If this happens
- *     during the measurement, the result can be anywhere between the
- *     low and high frequencies. Also, if you're interested in the
- *     high frequency value only, this function might return the low one
- *     instead.<br>
- * iii) On SMP systems exhibiting TSC drift (see \ref cpu_rdtsc)
- *
- * the quad_check option will run four consecutive measurements and
- * then return the average of the two most-consistent results. The total
- * runtime of the function will still be `millis' - consider using
- * a bit more time for the timing interval.
- *
- * Finally, for benchmarking / CPU intensive applications, the best strategy is
- * to use the cpu_tsc_mark() / cpu_tsc_unmark() / cpu_clock_by_mark() method.
- * Begin by mark()-ing about one second after application startup (allowing the
- * power-saving manager to kick in and rise the frequency during that time),
- * then unmark() just before application finishing. The result will most
- * acurately represent at what frequency your app was running.
- *
- * @returns the CPU clock frequency in MHz (within some measurement error
- * margin). If RDTSC is not supported, the result is -1.
- */
-int cpu_clock_measure(int millis, int quad_check);
-
-/**
- * @brief Measure the CPU clock frequency using instruction-counting
- *
- * @param millis - how much time to allocate for each run, in milliseconds
- * @param runs - how many runs to perform
- *
- * The function performs a busy-wait cycle using a known number of "heavy" (SSE)
- * instructions. These instructions run at (more or less guaranteed) 1 IPC rate,
- * so by running a busy loop for a fixed amount of time, and measuring the
- * amount of instructions done, the CPU clock is accurately measured.
- *
- * Of course, this function is still affected by the power-saving schemes, so
- * the warnings as of cpu_clock_measure() still apply. However, this function is
- * immune to problems with detection, related to the Intel Nehalem's "Turbo"
- * mode, where the internal clock is raised, but the RDTSC rate is unaffected.
- *
- * The function will run for about (millis * runs) milliseconds.
- * You can make only a single busy-wait run (runs == 1); however, this can
- * be affected by task scheduling (which will break the counting), so allowing
- * more than one run is recommended. As run length is not imperative for
- * accurate readings (e.g., 50ms is sufficient), you can afford a lot of short
- * runs, e.g. 10 runs of 50ms or 20 runs of 25ms.
- *
- * Recommended values - millis = 50, runs = 4. For more robustness,
- * increase the number of runs.
- * 
- * NOTE: on Bulldozer and later CPUs, the busy-wait cycle runs at 1.4 IPC, thus
- * the results are skewed. This is corrected internally by dividing the resulting
- * value by 1.4.
- * However, this only occurs if the thread is executed on a single CMT
- * module - if there are other threads competing for resources, the results are
- * unpredictable. Make sure you run cpu_clock_by_ic() on a CPU that is free from
- * competing threads, or if there are such threads, they shouldn't exceed the
- * number of modules. On a Bulldozer X8, that means 4 threads.
- *
- * @returns the CPU clock frequency in MHz (within some measurement error
- * margin). If SSE is not supported, the result is -1. If the input parameters
- * are incorrect, or some other internal fault is detected, the result is -2.
- */
-int cpu_clock_by_ic(int millis, int runs);
-
-/**
- * @brief Get the CPU clock frequency (all-in-one method)
- *
- * This is an all-in-one method for getting the CPU clock frequency.
- * It tries to use the OS for that. If the OS doesn't have this info, it
- * uses cpu_clock_measure with 200ms time interval and quadruple checking.
- *
- * @returns the CPU clock frequency in MHz. If every possible method fails,
- * the result is -1.
- */
-int cpu_clock(void);
-
-
 /**
  * @brief The return value of cpuid_get_epc().
  * @details
@@ -916,230 +667,6 @@ struct cpu_epc_t cpuid_get_epc(int index, const struct cpu_raw_data_t* raw);
  */
 const char* cpuid_lib_version(void);
 
-typedef void (*libcpuid_warn_fn_t) (const char *msg);
-/**
- * @brief Sets the warning print function
- *
- * In some cases, the internal libcpuid machinery would like to emit useful
- * debug warnings. By default, these warnings are written to stderr. However,
- * you can set a custom function that will receive those warnings.
- *
- * @param warn_fun - the warning function you want to set. If NULL, warnings
- *                   are disabled. The function takes const char* argument.
- *
- * @returns the current warning function. You can use the return value to
- * keep the previous warning function and restore it at your discretion.
- */
-libcpuid_warn_fn_t cpuid_set_warn_function(libcpuid_warn_fn_t warn_fun);
-
-/**
- * @brief Sets the verbosiness level
- *
- * When the verbosiness level is above zero, some functions might print
- * diagnostic information about what are they doing. The higher the level is,
- * the more detail is printed. Level zero is guaranteed to omit all such
- * output. The output is written using the same machinery as the warnings,
- * @see cpuid_set_warn_function()
- *
- * @param level the desired verbosiness level. Useful values 0..2 inclusive
- */
-void cpuid_set_verbosiness_level(int level);
-
-
-/**
- * @brief Obtains the CPU vendor from CPUID from the current CPU
- * @note The result is cached.
- * @returns VENDOR_UNKNOWN if failed, otherwise the CPU vendor type.
- *          @see cpu_vendor_t
- */
-cpu_vendor_t cpuid_get_vendor(void);
-
-/**
- * @brief a structure that holds a list of processor names
- */
-struct cpu_list_t {
-	/** Number of entries in the list */
-	int num_entries;
-	/** Pointers to names. There will be num_entries of them */
-	char **names;
-};
-
-/**
- * @brief Gets a list of all known CPU names from a specific vendor.
- *
- * This function compiles a list of all known CPU (code)names
- * (i.e. the possible values of cpu_id_t::cpu_codename) for the given vendor.
- *
- * There are about 100 entries for Intel and AMD, and a few for the other
- * vendors. The list is written out in approximate chronological introduction
- * order of the parts.
- *
- * @param vendor the vendor to be queried
- * @param list [out] the resulting list will be written here.
- * NOTE: As the memory is dynamically allocated, be sure to call
- *       cpuid_free_cpu_list() after you're done with the data
- * @see cpu_list_t
- */
-void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list);
-
-/**
- * @brief Frees a CPU list
- *
- * This function deletes all the memory associated with a CPU list, as obtained
- * by cpuid_get_cpu_list()
- *
- * @param list - the list to be free()'d.
- */
-void cpuid_free_cpu_list(struct cpu_list_t* list);
-
-struct msr_driver_t;
-/**
- * @brief Starts/opens a driver, needed to read MSRs (Model Specific Registers)
- *
- * On systems that support it, this function will create a temporary
- * system driver, that has privileges to execute the RDMSR instruction.
- * After the driver is created, you can read MSRs by calling \ref cpu_rdmsr
- *
- * @returns a handle to the driver on success, and NULL on error.
- *          The error message can be obtained by calling \ref cpuid_error.
- *          @see cpu_error_t
- */
-struct msr_driver_t* cpu_msr_driver_open(void);
-
-/**
- * @brief Similar to \ref cpu_msr_driver_open, but accept one parameter
- *
- * This function works on certain operating systems (GNU/Linux, FreeBSD)
- *
- * @param core_num specify the core number for MSR.
- *          The first core number is 0.
- *          The last core number is \ref cpuid_get_total_cpus - 1.
- *
- * @returns a handle to the driver on success, and NULL on error.
- *          The error message can be obtained by calling \ref cpuid_error.
- *          @see cpu_error_t
- */
-struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num);
-
-/**
- * @brief Reads a Model-Specific Register (MSR)
- *
- * If the CPU has MSRs (as indicated by the CPU_FEATURE_MSR flag), you can
- * read a MSR with the given index by calling this function.
- *
- * There are several prerequisites you must do before reading MSRs:
- * 1) You must ensure the CPU has RDMSR. Check the CPU_FEATURE_MSR flag
- *    in cpu_id_t::flags
- * 2) You must ensure that the CPU implements the specific MSR you intend to
- *    read.
- * 3) You must open a MSR-reader driver. RDMSR is a privileged instruction and
- *    needs ring-0 access in order to work. This temporary driver is created
- *    by calling \ref cpu_msr_driver_open
- *
- * @param handle - a handle to the MSR reader driver, as created by
- *                 cpu_msr_driver_open
- * @param msr_index - the numeric ID of the MSR you want to read
- * @param result - a pointer to a 64-bit integer, where the MSR value is stored
- *
- * @returns zero if successful, and some negative number on error.
- *          The error message can be obtained by calling \ref cpuid_error.
- *          @see cpu_error_t
- */
-int cpu_rdmsr(struct msr_driver_t* handle, uint32_t msr_index, uint64_t* result);
-
-
-typedef enum {
-	INFO_MPERF,                /*!< Maximum performance frequency clock. This
-                                    is a counter, which increments as a
-                                    proportion of the actual processor speed. */
-	INFO_APERF,                /*!< Actual performance frequency clock. This
-                                    accumulates the core clock counts when the
-                                    core is active. */
-	INFO_MIN_MULTIPLIER,       /*!< Minimum CPU:FSB ratio for this CPU,
-                                    multiplied by 100. */
-	INFO_CUR_MULTIPLIER,       /*!< Current CPU:FSB ratio, multiplied by 100.
-                                    e.g., a CPU:FSB value of 18.5 reads as
-                                    "1850". */
-	INFO_MAX_MULTIPLIER,       /*!< Maximum CPU:FSB ratio for this CPU,
-                                    multiplied by 100. */
-	INFO_TEMPERATURE,          /*!< The current core temperature in Celsius. */
-	INFO_THROTTLING,           /*!< 1 if the current logical processor is
-                                    throttling. 0 if it is running normally. */
-	INFO_VOLTAGE,              /*!< The current core voltage in Volt,
-	                            multiplied by 100. */
-	INFO_BCLK,                 /*!< See \ref INFO_BUS_CLOCK. */
-	INFO_BUS_CLOCK,            /*!< The main bus clock in MHz,
-	                            e.g., FSB/QPI/DMI/HT base clock,
-	                            multiplied by 100. */
-} cpu_msrinfo_request_t;
-
-/**
- * @brief Similar to \ref cpu_rdmsr, but extract a range of bits
- *
- * @param handle - a handle to the MSR reader driver, as created by
- *                 cpu_msr_driver_open
- * @param msr_index - the numeric ID of the MSR you want to read
- * @param highbit - the high bit in range, must be inferior to 64
- * @param lowbit - the low bit in range, must be equal or superior to 0
- * @param result - a pointer to a 64-bit integer, where the MSR value is stored
- *
- * @returns zero if successful, and some negative number on error.
- *          The error message can be obtained by calling \ref cpuid_error.
- *          @see cpu_error_t
- */
-int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit,
-                    uint8_t lowbit, uint64_t* result);
-
-/**
- * @brief Reads extended CPU information from Model-Specific Registers.
- * @param handle - a handle to an open MSR driver, @see cpu_msr_driver_open
- * @param which - which info field should be returned. A list of
- *                available information entities is listed in the
- *                cpu_msrinfo_request_t enum.
- * @retval - if the requested information is available for the current
- *           processor model, the respective value is returned.
- *           if no information is available, or the CPU doesn't support
- *           the query, the special value CPU_INVALID_VALUE is returned
- * @note This function is not MT-safe. If you intend to call it from multiple
- *       threads, guard it through a mutex or a similar primitive.
- */
-int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which);
-#define CPU_INVALID_VALUE 0x3fffffff
-
-/**
- * @brief Writes the raw MSR data to a text file
- * @param data - a pointer to msr_driver_t structure
- * @param filename - the path of the file, where the serialized data should be
- *                   written. If empty, stdout will be used.
- * @note This is intended primarily for debugging. On some processor, which is
- *       not currently supported or not completely recognized by cpu_identify,
- *       one can still successfully get the raw data and write it to a file.
- *       libcpuid developers can later import this file and debug the detection
- *       code as if running on the actual hardware.
- *       The file is simple text format of "something=value" pairs. Version info
- *       is also written, but the format is not intended to be neither backward-
- *       nor forward compatible.
- * @returns zero if successful, and some negative number on error.
- *          The error message can be obtained by calling \ref cpuid_error.
- *          @see cpu_error_t
- */
-int msr_serialize_raw_data(struct msr_driver_t* handle, const char* filename);
-
-/**
- * @brief Closes an open MSR driver
- *
- * This function unloads the MSR driver opened by cpu_msr_driver_open and
- * frees any resources associated with it.
- *
- * @param handle - a handle to the MSR reader driver, as created by
- *                 cpu_msr_driver_open
- *
- * @returns zero if successful, and some negative number on error.
- *          The error message can be obtained by calling \ref cpuid_error.
- *          @see cpu_error_t
- */
-int cpu_msr_driver_close(struct msr_driver_t* handle);
-
 #ifdef __cplusplus
 }; /* extern "C" */
 #endif
diff --git a/compat/libcpuid/libcpuid_constants.h b/src/3rdparty/libcpuid/libcpuid_constants.h
similarity index 100%
rename from compat/libcpuid/libcpuid_constants.h
rename to src/3rdparty/libcpuid/libcpuid_constants.h
diff --git a/compat/libcpuid/libcpuid_internal.h b/src/3rdparty/libcpuid/libcpuid_internal.h
similarity index 66%
rename from compat/libcpuid/libcpuid_internal.h
rename to src/3rdparty/libcpuid/libcpuid_internal.h
index 7f3671da6..038aa2092 100644
--- a/compat/libcpuid/libcpuid_internal.h
+++ b/src/3rdparty/libcpuid/libcpuid_internal.h
@@ -58,6 +58,48 @@ struct internal_id_info_t {
 	int score; // detection (matchtable) score
 };
 
+#define LBIT(x) (((long long) 1) << x)
+
+enum _common_bits_t {
+	_M_                     = LBIT(  0 ),
+	MOBILE_                 = LBIT(  1 ),
+	_MP_                    = LBIT(  2 ),
+};
+
+// additional detection bits for Intel CPUs:
+enum _intel_bits_t {
+	PENTIUM_                = LBIT( 10 ),
+	CELERON_                = LBIT( 11 ),
+	CORE_                   = LBIT( 12 ),
+	_I_                     = LBIT( 13 ),
+	_3                      = LBIT( 14 ),
+	_5                      = LBIT( 15 ),
+	_7                      = LBIT( 16 ),
+	XEON_                   = LBIT( 17 ),
+	ATOM_                   = LBIT( 18 ),
+};
+typedef enum _intel_bits_t intel_bits_t;
+
+enum _amd_bits_t {
+	ATHLON_      = LBIT( 10 ),
+	_XP_         = LBIT( 11 ),
+	DURON_       = LBIT( 12 ),
+	SEMPRON_     = LBIT( 13 ),
+	OPTERON_     = LBIT( 14 ),
+	TURION_      = LBIT( 15 ),
+	_LV_         = LBIT( 16 ),
+	_64_         = LBIT( 17 ),
+	_X2          = LBIT( 18 ),
+	_X3          = LBIT( 19 ),
+	_X4          = LBIT( 20 ),
+	_X6          = LBIT( 21 ),
+	_FX          = LBIT( 22 ),
+	_APU_        = LBIT( 23 ),
+};
+typedef enum _amd_bits_t amd_bits_t;
+
+
+
 int cpu_ident_internal(struct cpu_raw_data_t* raw, struct cpu_id_t* data, 
 		       struct internal_id_info_t* internal);
 
diff --git a/compat/libcpuid/libcpuid_types.h b/src/3rdparty/libcpuid/libcpuid_types.h
similarity index 100%
rename from compat/libcpuid/libcpuid_types.h
rename to src/3rdparty/libcpuid/libcpuid_types.h
diff --git a/src/3rdparty/libcpuid/libcpuid_util.c b/src/3rdparty/libcpuid/libcpuid_util.c
new file mode 100644
index 000000000..440b3724e
--- /dev/null
+++ b/src/3rdparty/libcpuid/libcpuid_util.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2008  Veselin Georgiev,
+ * anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include "libcpuid.h"
+#include "libcpuid_util.h"
+
+void match_features(const struct feature_map_t* matchtable, int count, uint32_t reg, struct cpu_id_t* data)
+{
+	int i;
+	for (i = 0; i < count; i++)
+		if (reg & (1u << matchtable[i].bit))
+			data->flags[matchtable[i].feature] = 1;
+}
+
+static int xmatch_entry(char c, const char* p)
+{
+	int i, j;
+	if (c == 0) return -1;
+	if (c == p[0]) return 1;
+	if (p[0] == '.') return 1;
+	if (p[0] == '#' && isdigit(c)) return 1;
+	if (p[0] == '[') {
+		j = 1;
+		while (p[j] && p[j] != ']') j++;
+		if (!p[j]) return -1;
+		for (i = 1; i < j; i++)
+			if (p[i] == c) return j + 1;
+	}
+	return -1;
+}
+
+int match_pattern(const char* s, const char* p)
+{
+	int i, j, dj, k, n, m;
+	n = (int) strlen(s);
+	m = (int) strlen(p);
+	for (i = 0; i < n; i++) {
+		if (xmatch_entry(s[i], p) != -1) {
+			j = 0;
+			k = 0;
+			while (j < m && ((dj = xmatch_entry(s[i + k], p + j)) != -1)) {
+				k++;
+				j += dj;
+			}
+			if (j == m) return i + 1;
+		}
+	}
+	return 0;
+}
+
+struct cpu_id_t* get_cached_cpuid(void)
+{
+	static int initialized = 0;
+	static struct cpu_id_t id;
+	if (initialized) return &id;
+	if (cpu_identify(NULL, &id))
+		memset(&id, 0, sizeof(id));
+	initialized = 1;
+	return &id;
+}
+
+int match_all(uint64_t bits, uint64_t mask)
+{
+	return (bits & mask) == mask;
+}
diff --git a/compat/libcpuid/libcpuid_util.h b/src/3rdparty/libcpuid/libcpuid_util.h
similarity index 84%
rename from compat/libcpuid/libcpuid_util.h
rename to src/3rdparty/libcpuid/libcpuid_util.h
index aba63f1a9..0c8200e86 100644
--- a/compat/libcpuid/libcpuid_util.h
+++ b/src/3rdparty/libcpuid/libcpuid_util.h
@@ -28,8 +28,6 @@
 
 #define COUNT_OF(array) (sizeof(array) / sizeof(array[0]))
 
-#define LBIT(x) (((long long) 1) << x)
-
 struct feature_map_t {
 	unsigned bit;
 	cpu_feature_t feature;
@@ -50,20 +48,6 @@ struct match_entry_t {
 int match_cpu_codename(const struct match_entry_t* matchtable, int count,
                        struct cpu_id_t* data, int brand_code, uint64_t bits,
                        int model_code);
-
-void warnf(const char* format, ...)
-#ifdef __GNUC__
-__attribute__((format(printf, 1, 2)))
-#endif
-;
-void debugf(int verboselevel, const char* format, ...)
-#ifdef __GNUC__
-__attribute__((format(printf, 2, 3)))
-#endif
-;
-void generic_get_cpu_list(const struct match_entry_t* matchtable, int count,
-                          struct cpu_list_t* list);
-
 /*
  * Seek for a pattern in `haystack'.
  * Pattern may be an fixed string, or contain the special metacharacters
@@ -86,15 +70,9 @@ struct cpu_id_t* get_cached_cpuid(void);
 /* returns true if all bits of mask are present in `bits'. */
 int match_all(uint64_t bits, uint64_t mask);
 
-/* print what bits a mask consists of */
-void debug_print_lbits(int debuglevel, uint64_t mask);
-
 /*
  * Sets the current errno
  */
 int set_error(cpu_error_t err);
 
-extern libcpuid_warn_fn_t _warn_fun;
-extern int _current_verboselevel;
-
 #endif /* __LIBCPUID_UTIL_H__ */
diff --git a/src/3rdparty/libcpuid/recog_amd.c b/src/3rdparty/libcpuid/recog_amd.c
new file mode 100644
index 000000000..352d733b8
--- /dev/null
+++ b/src/3rdparty/libcpuid/recog_amd.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2008  Veselin Georgiev,
+ * anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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>
+#include <string.h>
+#include <ctype.h>
+#include "libcpuid.h"
+#include "libcpuid_util.h"
+#include "libcpuid_internal.h"
+#include "recog_amd.h"
+
+const struct amd_code_str { amd_code_t code; char *str; } amd_code_str[] = {
+	#define CODE(x) { x, #x }
+	#define CODE2(x, y) CODE(x)
+	#include "amd_code_t.h"
+	#undef CODE
+};
+
+struct amd_code_and_bits_t {
+	int code;
+	uint64_t bits;
+};
+
+enum _amd_model_codes_t {
+	// Only for Ryzen CPUs:
+	_1400,
+	_1500,
+	_1600,
+};
+
+static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	const struct feature_map_t matchtable_edx81[] = {
+		{ 20, CPU_FEATURE_NX },
+		{ 22, CPU_FEATURE_MMXEXT },
+		{ 25, CPU_FEATURE_FXSR_OPT },
+		{ 30, CPU_FEATURE_3DNOWEXT },
+		{ 31, CPU_FEATURE_3DNOW },
+	};
+	const struct feature_map_t matchtable_ecx81[] = {
+		{  1, CPU_FEATURE_CMP_LEGACY },
+		{  2, CPU_FEATURE_SVM },
+		{  5, CPU_FEATURE_ABM },
+		{  6, CPU_FEATURE_SSE4A },
+		{  7, CPU_FEATURE_MISALIGNSSE },
+		{  8, CPU_FEATURE_3DNOWPREFETCH },
+		{  9, CPU_FEATURE_OSVW },
+		{ 10, CPU_FEATURE_IBS },
+		{ 11, CPU_FEATURE_XOP },
+		{ 12, CPU_FEATURE_SKINIT },
+		{ 13, CPU_FEATURE_WDT },
+		{ 16, CPU_FEATURE_FMA4 },
+		{ 21, CPU_FEATURE_TBM },
+	};
+	const struct feature_map_t matchtable_edx87[] = {
+		{  0, CPU_FEATURE_TS },
+		{  1, CPU_FEATURE_FID },
+		{  2, CPU_FEATURE_VID },
+		{  3, CPU_FEATURE_TTP },
+		{  4, CPU_FEATURE_TM_AMD },
+		{  5, CPU_FEATURE_STC },
+		{  6, CPU_FEATURE_100MHZSTEPS },
+		{  7, CPU_FEATURE_HWPSTATE },
+		/* id 8 is handled in common */
+		{  9, CPU_FEATURE_CPB },
+		{ 10, CPU_FEATURE_APERFMPERF },
+		{ 11, CPU_FEATURE_PFI },
+		{ 12, CPU_FEATURE_PA },
+	};
+	if (raw->ext_cpuid[0][0] >= 0x80000001) {
+		match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data);
+		match_features(matchtable_ecx81, COUNT_OF(matchtable_ecx81), raw->ext_cpuid[1][2], data);
+	}
+	if (raw->ext_cpuid[0][0] >= 0x80000007)
+		match_features(matchtable_edx87, COUNT_OF(matchtable_edx87), raw->ext_cpuid[7][3], data);
+	if (raw->ext_cpuid[0][0] >= 0x8000001a) {
+		/* We have the extended info about SSE unit size */
+		data->detection_hints[CPU_HINT_SSE_SIZE_AUTH] = 1;
+		data->sse_size = (raw->ext_cpuid[0x1a][0] & 1) ? 128 : 64;
+	}
+}
+
+static void decode_amd_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	int l3_result;
+	const int assoc_table[16] = {
+		0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, 255
+	};
+	unsigned n = raw->ext_cpuid[0][0];
+	
+	if (n >= 0x80000005) {
+		data->l1_data_cache = (raw->ext_cpuid[5][2] >> 24) & 0xff;
+		data->l1_assoc = (raw->ext_cpuid[5][2] >> 16) & 0xff;
+		data->l1_cacheline = (raw->ext_cpuid[5][2]) & 0xff;
+		data->l1_instruction_cache = (raw->ext_cpuid[5][3] >> 24) & 0xff;
+	}
+	if (n >= 0x80000006) {
+		data->l2_cache = (raw->ext_cpuid[6][2] >> 16) & 0xffff;
+		data->l2_assoc = assoc_table[(raw->ext_cpuid[6][2] >> 12) & 0xf];
+		data->l2_cacheline = (raw->ext_cpuid[6][2]) & 0xff;
+		
+		l3_result = (raw->ext_cpuid[6][3] >> 18);
+		if (l3_result > 0) {
+			l3_result = 512 * l3_result; /* AMD spec says it's a range,
+			                                but we take the lower bound */
+			data->l3_cache = l3_result;
+			data->l3_assoc = assoc_table[(raw->ext_cpuid[6][3] >> 12) & 0xf];
+			data->l3_cacheline = (raw->ext_cpuid[6][3]) & 0xff;
+		} else {
+			data->l3_cache = 0;
+		}
+	}
+}
+
+static void decode_amd_number_of_cores(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	int logical_cpus = -1, num_cores = -1;
+	
+	if (raw->basic_cpuid[0][0] >= 1) {
+		logical_cpus = (raw->basic_cpuid[1][1] >> 16) & 0xff;
+		if (raw->ext_cpuid[0][0] >= 8) {
+			num_cores = 1 + (raw->ext_cpuid[8][2] & 0xff);
+		}
+	}
+	if (data->flags[CPU_FEATURE_HT]) {
+		if (num_cores > 1) {
+			if (data->ext_family >= 23)
+				num_cores /= 2; // e.g., Ryzen 7 reports 16 "real" cores, but they are really just 8.
+			data->num_cores = num_cores;
+			data->num_logical_cpus = logical_cpus;
+		} else {
+			data->num_cores = 1;
+			data->num_logical_cpus = (logical_cpus >= 2 ? logical_cpus : 2);
+		}
+	} else {
+		data->num_cores = data->num_logical_cpus = 1;
+	}
+}
+
+int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal)
+{
+	load_amd_features(raw, data);
+	decode_amd_cache_info(raw, data);
+	decode_amd_number_of_cores(raw, data);
+	return 0;
+}
diff --git a/compat/libcpuid/recog_amd.h b/src/3rdparty/libcpuid/recog_amd.h
similarity index 96%
rename from compat/libcpuid/recog_amd.h
rename to src/3rdparty/libcpuid/recog_amd.h
index 34e895983..19f839ba2 100644
--- a/compat/libcpuid/recog_amd.h
+++ b/src/3rdparty/libcpuid/recog_amd.h
@@ -27,6 +27,5 @@
 #define __RECOG_AMD_H__
 
 int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal);
-void cpuid_get_list_amd(struct cpu_list_t* list);
 
 #endif /* __RECOG_AMD_H__ */
diff --git a/src/3rdparty/libcpuid/recog_intel.c b/src/3rdparty/libcpuid/recog_intel.c
new file mode 100644
index 000000000..5467c19f0
--- /dev/null
+++ b/src/3rdparty/libcpuid/recog_intel.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright 2008  Veselin Georgiev,
+ * anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <string.h>
+#include <ctype.h>
+#include "libcpuid.h"
+#include "libcpuid_util.h"
+#include "libcpuid_internal.h"
+#include "recog_intel.h"
+
+const struct intel_bcode_str { intel_code_t code; char *str; } intel_bcode_str[] = {
+	#define CODE(x) { x, #x }
+	#define CODE2(x, y) CODE(x)
+	#include "intel_code_t.h"
+	#undef CODE
+};
+
+typedef struct {
+	int code;
+	uint64_t bits;
+} intel_code_and_bits_t;
+
+enum _intel_model_t {
+	UNKNOWN = -1,
+	_3000 = 100,
+	_3100,
+	_3200,
+	X3200,
+	_3300,
+	X3300,
+	_5100,
+	_5200,
+	_5300,
+	_5400,
+	_2xxx, /* Core i[357] 2xxx */
+	_3xxx, /* Core i[357] 3xxx */
+};
+typedef enum _intel_model_t intel_model_t;
+
+static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	const struct feature_map_t matchtable_edx1[] = {
+		{ 18, CPU_FEATURE_PN },
+		{ 21, CPU_FEATURE_DTS },
+		{ 22, CPU_FEATURE_ACPI },
+		{ 27, CPU_FEATURE_SS },
+		{ 29, CPU_FEATURE_TM },
+		{ 30, CPU_FEATURE_IA64 },
+		{ 31, CPU_FEATURE_PBE },
+	};
+	const struct feature_map_t matchtable_ecx1[] = {
+		{  2, CPU_FEATURE_DTS64 },
+		{  4, CPU_FEATURE_DS_CPL },
+		{  5, CPU_FEATURE_VMX },
+		{  6, CPU_FEATURE_SMX },
+		{  7, CPU_FEATURE_EST },
+		{  8, CPU_FEATURE_TM2 },
+		{ 10, CPU_FEATURE_CID },
+		{ 14, CPU_FEATURE_XTPR },
+		{ 15, CPU_FEATURE_PDCM },
+		{ 18, CPU_FEATURE_DCA },
+		{ 21, CPU_FEATURE_X2APIC },
+	};
+	const struct feature_map_t matchtable_edx81[] = {
+		{ 20, CPU_FEATURE_XD },
+	};
+	const struct feature_map_t matchtable_ebx7[] = {
+		{  2, CPU_FEATURE_SGX },
+		{  4, CPU_FEATURE_HLE },
+		{ 11, CPU_FEATURE_RTM },
+		{ 16, CPU_FEATURE_AVX512F },
+		{ 17, CPU_FEATURE_AVX512DQ },
+		{ 18, CPU_FEATURE_RDSEED },
+		{ 19, CPU_FEATURE_ADX },
+		{ 26, CPU_FEATURE_AVX512PF },
+		{ 27, CPU_FEATURE_AVX512ER },
+		{ 28, CPU_FEATURE_AVX512CD },
+		{ 29, CPU_FEATURE_SHA_NI },
+		{ 30, CPU_FEATURE_AVX512BW },
+		{ 31, CPU_FEATURE_AVX512VL },
+	};
+	if (raw->basic_cpuid[0][0] >= 1) {
+		match_features(matchtable_edx1, COUNT_OF(matchtable_edx1), raw->basic_cpuid[1][3], data);
+		match_features(matchtable_ecx1, COUNT_OF(matchtable_ecx1), raw->basic_cpuid[1][2], data);
+	}
+	if (raw->ext_cpuid[0][0] >= 1) {
+		match_features(matchtable_edx81, COUNT_OF(matchtable_edx81), raw->ext_cpuid[1][3], data);
+	}
+	// detect TSX/AVX512:
+	if (raw->basic_cpuid[0][0] >= 7) {
+		match_features(matchtable_ebx7, COUNT_OF(matchtable_ebx7), raw->basic_cpuid[7][1], data);
+	}
+}
+
+enum _cache_type_t {
+	L1I,
+	L1D,
+	L2,
+	L3,
+	L4
+};
+typedef enum _cache_type_t cache_type_t;
+
+static void check_case(uint8_t on, cache_type_t cache, int size, int assoc, int linesize, struct cpu_id_t* data)
+{
+	if (!on) return;
+	switch (cache) {
+		case L1I:
+			data->l1_instruction_cache = size;
+			break;
+		case L1D:
+			data->l1_data_cache = size;
+			data->l1_assoc = assoc;
+			data->l1_cacheline = linesize;
+			break;
+		case L2:
+			data->l2_cache = size;
+			data->l2_assoc = assoc;
+			data->l2_cacheline = linesize;
+			break;
+		case L3:
+			data->l3_cache = size;
+			data->l3_assoc = assoc;
+			data->l3_cacheline = linesize;
+			break;
+		case L4:
+			data->l4_cache = size;
+			data->l4_assoc = assoc;
+			data->l4_cacheline = linesize;
+			break;
+		default:
+			break;
+	}
+}
+
+static void decode_intel_oldstyle_cache_info(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	uint8_t f[256] = {0};
+	int reg, off;
+	uint32_t x;
+	for (reg = 0; reg < 4; reg++) {
+		x = raw->basic_cpuid[2][reg];
+		if (x & 0x80000000) continue;
+		for (off = 0; off < 4; off++) {
+			f[x & 0xff] = 1;
+			x >>= 8;
+		}
+	}
+	
+	check_case(f[0x06], L1I,      8,  4,  32, data);
+	check_case(f[0x08], L1I,     16,  4,  32, data);
+	check_case(f[0x0A], L1D,      8,  2,  32, data);
+	check_case(f[0x0C], L1D,     16,  4,  32, data);
+	check_case(f[0x22],  L3,    512,  4,  64, data);
+	check_case(f[0x23],  L3,   1024,  8,  64, data);
+	check_case(f[0x25],  L3,   2048,  8,  64, data);
+	check_case(f[0x29],  L3,   4096,  8,  64, data);
+	check_case(f[0x2C], L1D,     32,  8,  64, data);
+	check_case(f[0x30], L1I,     32,  8,  64, data);
+	check_case(f[0x39],  L2,    128,  4,  64, data);
+	check_case(f[0x3A],  L2,    192,  6,  64, data);
+	check_case(f[0x3B],  L2,    128,  2,  64, data);
+	check_case(f[0x3C],  L2,    256,  4,  64, data);
+	check_case(f[0x3D],  L2,    384,  6,  64, data);
+	check_case(f[0x3E],  L2,    512,  4,  64, data);
+	check_case(f[0x41],  L2,    128,  4,  32, data);
+	check_case(f[0x42],  L2,    256,  4,  32, data);
+	check_case(f[0x43],  L2,    512,  4,  32, data);
+	check_case(f[0x44],  L2,   1024,  4,  32, data);
+	check_case(f[0x45],  L2,   2048,  4,  32, data);
+	check_case(f[0x46],  L3,   4096,  4,  64, data);
+	check_case(f[0x47],  L3,   8192,  8,  64, data);
+	check_case(f[0x4A],  L3,   6144, 12,  64, data);
+	check_case(f[0x4B],  L3,   8192, 16,  64, data);
+	check_case(f[0x4C],  L3,  12288, 12,  64, data);
+	check_case(f[0x4D],  L3,  16384, 16,  64, data);
+	check_case(f[0x4E],  L2,   6144, 24,  64, data);
+	check_case(f[0x60], L1D,     16,  8,  64, data);
+	check_case(f[0x66], L1D,      8,  4,  64, data);
+	check_case(f[0x67], L1D,     16,  4,  64, data);
+	check_case(f[0x68], L1D,     32,  4,  64, data);
+	/* The following four entries are trace cache. Intel does not
+	 * specify a cache-line size, so we use -1 instead
+	 */
+	check_case(f[0x70], L1I,     12,  8,  -1, data);
+	check_case(f[0x71], L1I,     16,  8,  -1, data);
+	check_case(f[0x72], L1I,     32,  8,  -1, data);
+	check_case(f[0x73], L1I,     64,  8,  -1, data);
+	
+	check_case(f[0x78],  L2,   1024,  4,  64, data);
+	check_case(f[0x79],  L2,    128,  8,  64, data);
+	check_case(f[0x7A],  L2,    256,  8,  64, data);
+	check_case(f[0x7B],  L2,    512,  8,  64, data);
+	check_case(f[0x7C],  L2,   1024,  8,  64, data);
+	check_case(f[0x7D],  L2,   2048,  8,  64, data);
+	check_case(f[0x7F],  L2,    512,  2,  64, data);
+	check_case(f[0x82],  L2,    256,  8,  32, data);
+	check_case(f[0x83],  L2,    512,  8,  32, data);
+	check_case(f[0x84],  L2,   1024,  8,  32, data);
+	check_case(f[0x85],  L2,   2048,  8,  32, data);
+	check_case(f[0x86],  L2,    512,  4,  64, data);
+	check_case(f[0x87],  L2,   1024,  8,  64, data);
+	
+	if (f[0x49]) {
+		/* This flag is overloaded with two meanings. On Xeon MP
+		 * (family 0xf, model 0x6) this means L3 cache. On all other
+		 * CPUs (notably Conroe et al), this is L2 cache. In both cases
+		 * it means 4MB, 16-way associative, 64-byte line size.
+		 */
+		if (data->family == 0xf && data->model == 0x6) {
+			data->l3_cache = 4096;
+			data->l3_assoc = 16;
+			data->l3_cacheline = 64;
+		} else {
+			data->l2_cache = 4096;
+			data->l2_assoc = 16;
+			data->l2_cacheline = 64;
+		}
+	}
+	if (f[0x40]) {
+		/* Again, a special flag. It means:
+		 * 1) If no L2 is specified, then CPU is w/o L2 (0 KB)
+		 * 2) If L2 is specified by other flags, then, CPU is w/o L3.
+		 */
+		if (data->l2_cache == -1) {
+			data->l2_cache = 0;
+		} else {
+			data->l3_cache = 0;
+		}
+	}
+}
+
+static void decode_intel_deterministic_cache_info(struct cpu_raw_data_t* raw,
+                                                  struct cpu_id_t* data)
+{
+	int ecx;
+	int ways, partitions, linesize, sets, size, level, typenumber;
+	cache_type_t type;
+	for (ecx = 0; ecx < MAX_INTELFN4_LEVEL; ecx++) {
+		typenumber = raw->intel_fn4[ecx][0] & 0x1f;
+		if (typenumber == 0) break;
+		level = (raw->intel_fn4[ecx][0] >> 5) & 0x7;
+		if (level == 1 && typenumber == 1)
+			type = L1D;
+		else if (level == 1 && typenumber == 2)
+			type = L1I;
+		else if (level == 2 && typenumber == 3)
+			type = L2;
+		else if (level == 3 && typenumber == 3)
+			type = L3;
+		else if (level == 4 && typenumber == 3)
+			type = L4;
+		else {
+			continue;
+		}
+		ways = ((raw->intel_fn4[ecx][1] >> 22) & 0x3ff) + 1;
+		partitions = ((raw->intel_fn4[ecx][1] >> 12) & 0x3ff) + 1;
+		linesize = (raw->intel_fn4[ecx][1] & 0xfff) + 1;
+		sets = raw->intel_fn4[ecx][2] + 1;
+		size = ways * partitions * linesize * sets / 1024;
+		check_case(1, type, size, ways, linesize, data);
+	}
+}
+
+static int decode_intel_extended_topology(struct cpu_raw_data_t* raw,
+                                           struct cpu_id_t* data)
+{
+	int i, level_type, num_smt = -1, num_core = -1;
+	for (i = 0; i < MAX_INTELFN11_LEVEL; i++) {
+		level_type = (raw->intel_fn11[i][2] & 0xff00) >> 8;
+		switch (level_type) {
+			case 0x01:
+				num_smt = raw->intel_fn11[i][1] & 0xffff;
+				break;
+			case 0x02:
+				num_core = raw->intel_fn11[i][1] & 0xffff;
+				break;
+			default:
+				break;
+		}
+	}
+	if (num_smt == -1 || num_core == -1) return 0;
+	data->num_logical_cpus = num_core;
+	data->num_cores = num_core / num_smt;
+	// make sure num_cores is at least 1. In VMs, the CPUID instruction
+	// is rigged and may give nonsensical results, but we should at least
+	// avoid outputs like data->num_cores == 0.
+	if (data->num_cores <= 0) data->num_cores = 1;
+	return 1;
+}
+
+static void decode_intel_number_of_cores(struct cpu_raw_data_t* raw,
+                                         struct cpu_id_t* data)
+{
+	int logical_cpus = -1, num_cores = -1;
+	
+	if (raw->basic_cpuid[0][0] >= 11) {
+		if (decode_intel_extended_topology(raw, data)) return;
+	}
+	
+	if (raw->basic_cpuid[0][0] >= 1) {
+		logical_cpus = (raw->basic_cpuid[1][1] >> 16) & 0xff;
+		if (raw->basic_cpuid[0][0] >= 4) {
+			num_cores = 1 + ((raw->basic_cpuid[4][0] >> 26) & 0x3f);
+		}
+	}
+	if (data->flags[CPU_FEATURE_HT]) {
+		if (num_cores > 1) {
+			data->num_cores = num_cores;
+			data->num_logical_cpus = logical_cpus;
+		} else {
+			data->num_cores = 1;
+			data->num_logical_cpus = (logical_cpus >= 1 ? logical_cpus : 1);
+			if (data->num_logical_cpus == 1)
+				data->flags[CPU_FEATURE_HT] = 0;
+		}
+	} else {
+		data->num_cores = data->num_logical_cpus = 1;
+	}
+}
+
+static intel_code_and_bits_t get_brand_code_and_bits(struct cpu_id_t* data)
+{
+	intel_code_t code = (intel_code_t) NC;
+	intel_code_and_bits_t result;
+	uint64_t bits = 0;
+	int i = 0;
+	const char* bs = data->brand_str;
+	const char* s;
+	const struct { intel_code_t c; const char *search; } matchtable[] = {
+		{ PENTIUM_M, "Pentium(R) M" },
+		{ CORE_SOLO, "Pentium(R) Dual  CPU" },
+		{ CORE_SOLO, "Pentium(R) Dual-Core" },
+		{ PENTIUM_D, "Pentium(R) D" },
+		{ CORE_SOLO, "Genuine Intel(R) CPU" },
+		{ CORE_SOLO, "Intel(R) Core(TM)" },
+		{ DIAMONDVILLE, "CPU [N ][23]## " },
+		{ SILVERTHORNE, "CPU Z" },
+		{ PINEVIEW, "CPU [ND][45]## " },
+		{ CEDARVIEW, "CPU [ND]#### " },
+	};
+	
+	const struct { uint64_t bit; const char* search; } bit_matchtable[] = {
+		{ XEON_, "Xeon" },
+		{ _MP_, " MP" },
+		{ ATOM_, "Atom(TM) CPU" },
+		{ MOBILE_, "Mobile" },
+		{ CELERON_, "Celeron" },
+		{ PENTIUM_, "Pentium" },
+	};
+	
+	for (i = 0; i < COUNT_OF(bit_matchtable); i++) {
+		if (match_pattern(bs, bit_matchtable[i].search))
+			bits |= bit_matchtable[i].bit;
+	}
+	
+	if ((i = match_pattern(bs, "Core(TM) [im][357]")) != 0) {
+		bits |= CORE_;
+		i--;
+		switch (bs[i + 9]) {
+			case 'i': bits |= _I_; break;
+			case 'm': bits |= _M_; break;
+		}
+		switch (bs[i + 10]) {
+			case '3': bits |= _3; break;
+			case '5': bits |= _5; break;
+			case '7': bits |= _7; break;
+		}
+	}
+	for (i = 0; i < COUNT_OF(matchtable); i++)
+		if (match_pattern(bs, matchtable[i].search)) {
+			code = matchtable[i].c;
+			break;
+		}
+	if (bits & XEON_) {
+		if (match_pattern(bs, "W35##") || match_pattern(bs, "[ELXW]75##"))
+			bits |= _7;
+		else if (match_pattern(bs, "[ELXW]55##"))
+			code = GAINESTOWN;
+		else if (match_pattern(bs, "[ELXW]56##"))
+			code = WESTMERE;
+		else if (data->l3_cache > 0 && data->family == 16)
+			/* restrict by family, since later Xeons also have L3 ... */
+			code = IRWIN;
+	}
+	if (match_all(bits, XEON_ + _MP_) && data->l3_cache > 0)
+		code = POTOMAC;
+	if (code == CORE_SOLO) {
+		s = strstr(bs, "CPU");
+		if (s) {
+			s += 3;
+			while (*s == ' ') s++;
+			if (*s == 'T')
+				bits |= MOBILE_;
+		}
+	}
+	if (code == CORE_SOLO) {
+		switch (data->num_cores) {
+			case 1: break;
+			case 2:
+			{
+				code = CORE_DUO;
+				if (data->num_logical_cpus > 2)
+					code = DUAL_CORE_HT;
+				break;
+			}
+			case 4:
+			{
+				code = QUAD_CORE;
+				if (data->num_logical_cpus > 4)
+					code = QUAD_CORE_HT;
+				break;
+			}
+			default:
+				code = MORE_THAN_QUADCORE; break;
+		}
+	}
+	
+	if (code == CORE_DUO && (bits & MOBILE_) && data->model != 14) {
+		if (data->ext_model < 23) {
+			code = MEROM;
+		} else {
+			code = PENRYN;
+		}
+	}
+	if (data->ext_model == 23 &&
+		(code == CORE_DUO || code == PENTIUM_D || (bits & CELERON_))) {
+		code = WOLFDALE;
+	}
+
+	result.code = code;
+	result.bits = bits;
+	return result;
+}
+
+static void decode_intel_sgx_features(const struct cpu_raw_data_t* raw, struct cpu_id_t* data)
+{
+	struct cpu_epc_t epc;
+	int i;
+	
+	if (raw->basic_cpuid[0][0] < 0x12) return; // no 12h leaf
+	if (raw->basic_cpuid[0x12][0] == 0) return; // no sub-leafs available, probably it's disabled by BIOS
+	
+	// decode sub-leaf 0:
+	if (raw->basic_cpuid[0x12][0] & 1) data->sgx.flags[INTEL_SGX1] = 1;
+	if (raw->basic_cpuid[0x12][0] & 2) data->sgx.flags[INTEL_SGX2] = 1;
+	if (data->sgx.flags[INTEL_SGX1] || data->sgx.flags[INTEL_SGX2])
+		data->sgx.present = 1;
+	data->sgx.misc_select = raw->basic_cpuid[0x12][1];
+	data->sgx.max_enclave_32bit = (raw->basic_cpuid[0x12][3]     ) & 0xff;
+	data->sgx.max_enclave_64bit = (raw->basic_cpuid[0x12][3] >> 8) & 0xff;
+	
+	// decode sub-leaf 1:
+	data->sgx.secs_attributes = raw->intel_fn12h[1][0] | (((uint64_t) raw->intel_fn12h[1][1]) << 32);
+	data->sgx.secs_xfrm       = raw->intel_fn12h[1][2] | (((uint64_t) raw->intel_fn12h[1][3]) << 32);
+	
+	// decode higher-order subleafs, whenever present:
+	data->sgx.num_epc_sections = -1;
+	for (i = 0; i < 1000000; i++) {
+		epc = cpuid_get_epc(i, raw);
+		if (epc.length == 0) {
+			data->sgx.num_epc_sections = i;
+			break;
+		}
+	}
+	if (data->sgx.num_epc_sections == -1) {
+		data->sgx.num_epc_sections = 1000000;
+	}
+}
+
+struct cpu_epc_t cpuid_get_epc(int index, const struct cpu_raw_data_t* raw)
+{
+	uint32_t regs[4];
+	struct cpu_epc_t retval = {0, 0};
+	if (raw && index < MAX_INTELFN12H_LEVEL - 2) {
+		// this was queried already, use the data:
+		memcpy(regs, raw->intel_fn12h[2 + index], sizeof(regs));
+	} else {
+		// query this ourselves:
+		regs[0] = 0x12;
+		regs[2] = 2 + index;
+		regs[1] = regs[3] = 0;
+		cpu_exec_cpuid_ext(regs);
+	}
+	
+	// decode values:
+	if ((regs[0] & 0xf) == 0x1) {
+		retval.start_addr |= (regs[0] & 0xfffff000); // bits [12, 32) -> bits [12, 32)
+		retval.start_addr |= ((uint64_t) (regs[1] & 0x000fffff)) << 32; // bits [0, 20) -> bits [32, 52)
+		retval.length     |= (regs[2] & 0xfffff000); // bits [12, 32) -> bits [12, 32)
+		retval.length     |= ((uint64_t) (regs[3] & 0x000fffff)) << 32; // bits [0, 20) -> bits [32, 52)
+	}
+	return retval;
+}
+
+int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal)
+{
+	intel_code_and_bits_t brand;
+
+	load_intel_features(raw, data);
+	if (raw->basic_cpuid[0][0] >= 4) {
+		/* Deterministic way is preferred, being more generic */
+		decode_intel_deterministic_cache_info(raw, data);
+	} else if (raw->basic_cpuid[0][0] >= 2) {
+		decode_intel_oldstyle_cache_info(raw, data);
+	}
+	decode_intel_number_of_cores(raw, data);
+
+	brand = get_brand_code_and_bits(data);
+	
+	internal->code.intel = brand.code;
+	internal->bits = brand.bits;
+	
+	if (data->flags[CPU_FEATURE_SGX]) {
+		// if SGX is indicated by the CPU, verify its presence:
+		decode_intel_sgx_features(raw, data);
+	}
+
+	return 0;
+}
diff --git a/compat/libcpuid/recog_intel.h b/src/3rdparty/libcpuid/recog_intel.h
similarity index 96%
rename from compat/libcpuid/recog_intel.h
rename to src/3rdparty/libcpuid/recog_intel.h
index b99c783bf..96676f3be 100644
--- a/compat/libcpuid/recog_intel.h
+++ b/src/3rdparty/libcpuid/recog_intel.h
@@ -27,6 +27,5 @@
 #define __RECOG_INTEL_H__
 
 int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal);
-void cpuid_get_list_intel(struct cpu_list_t* list);
 
 #endif /*__RECOG_INTEL_H__*/
diff --git a/compat/winansi.c b/src/3rdparty/winansi.cpp
similarity index 98%
rename from compat/winansi.c
rename to src/3rdparty/winansi.cpp
index 41cecd6ac..c6fbbc208 100644
--- a/compat/winansi.c
+++ b/src/3rdparty/winansi.cpp
@@ -11,7 +11,7 @@
 #include <stdio.h>
 #include <io.h>
 
-#include "compat/winansi.h"
+#include "winansi.h"
 /*
 * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
 */
@@ -344,8 +344,8 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list)
 #endif
     va_end(cp);
 
-    if (len > sizeof(small_buf) - 1) {
-        buf = malloc(len + 1);
+    if ((unsigned) len > sizeof(small_buf) - 1) {
+        buf = (char*)malloc(len + 1);
         if (!buf)
             goto abort;
 
@@ -389,4 +389,4 @@ int winansi_printf(const char *format, ...)
     va_end(list);
 
     return rv;
-}
\ No newline at end of file
+}
diff --git a/compat/winansi.h b/src/3rdparty/winansi.h
similarity index 92%
rename from compat/winansi.h
rename to src/3rdparty/winansi.h
index 70c137348..47914c364 100644
--- a/compat/winansi.h
+++ b/src/3rdparty/winansi.h
@@ -1,12 +1,11 @@
 /*
  * ANSI emulation wrappers
  */
-#ifdef WIN32
+
 #include <windows.h>
 #include <stddef.h>
 #include <stdio.h>
 
-#define isatty(fd) _isatty(fd)
 #define fileno(fd) _fileno(fd)
 
 #ifdef __cplusplus
@@ -28,5 +27,3 @@ extern "C" {
 #define printf winansi_printf
 #define fprintf winansi_fprintf
 #define vfprintf winansi_vfprintf
-
-#endif
\ No newline at end of file
diff --git a/src/App.cpp b/src/App.cpp
new file mode 100644
index 000000000..8f6ed1489
--- /dev/null
+++ b/src/App.cpp
@@ -0,0 +1,129 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+#include <uv.h>
+
+
+#include "App.h"
+#include "Console.h"
+#include "Cpu.h"
+#include "crypto/CryptoNight.h"
+#include "Mem.h"
+#include "net/Network.h"
+#include "Options.h"
+#include "Summary.h"
+#include "version.h"
+#include "workers/Workers.h"
+
+
+App *App::m_self = nullptr;
+
+
+
+App::App(int argc, char **argv) :
+    m_network(nullptr),
+    m_options(nullptr)
+{
+    m_self = this;
+
+    Console::init();
+    Cpu::init();
+
+    m_options = Options::parse(argc, argv);
+    m_network = new Network(m_options);
+
+    uv_signal_init(uv_default_loop(), &m_signal);
+}
+
+
+App::~App()
+{
+}
+
+
+int App::exec()
+{
+    if (!m_options->isReady()) {
+        return 0;
+    }
+
+    if (!CryptoNight::init(m_options->algo(), m_options->algoVariant())) {
+        LOG_ERR("\"%s\" hash self-test failed.", m_options->algoName());
+        return 1;
+    }
+
+    uv_signal_start(&m_signal, App::onSignal, SIGHUP);
+    uv_signal_start(&m_signal, App::onSignal, SIGTERM);
+    uv_signal_start(&m_signal, App::onSignal, SIGINT);
+
+    background();
+
+    Mem::allocate(m_options->algo(), m_options->threads(), m_options->doubleHash());
+    Summary::print();
+
+    Workers::start(m_options->affinity(), m_options->nicehash());
+
+    m_network->connect();
+
+    const int r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+    uv_loop_close(uv_default_loop());
+
+    free(m_network);
+    free(m_options);
+
+    Mem::release();
+
+    return r;
+}
+
+
+void App::close()
+{
+    uv_stop(uv_default_loop());
+}
+
+
+void App::onSignal(uv_signal_t *handle, int signum)
+{
+    switch (signum)
+    {
+    case SIGHUP:
+        LOG_WARN("SIGHUP received, exiting");
+        break;
+
+    case SIGTERM:
+        LOG_WARN("SIGTERM received, exiting");
+        break;
+
+    case SIGINT:
+        LOG_WARN("SIGINT received, exiting");
+        break;
+
+    default:
+        break;
+    }
+
+    m_self->close();
+}
diff --git a/compat.h b/src/App.h
similarity index 71%
rename from compat.h
rename to src/App.h
index bf488226e..99eac4329 100644
--- a/compat.h
+++ b/src/App.h
@@ -21,27 +21,37 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __COMPAT_H__
-#define __COMPAT_H__
+#ifndef __APP_H__
+#define __APP_H__
 
-#define unlikely(expr) (__builtin_expect(!!(expr), 0))
-#define likely(expr)   (__builtin_expect(!!(expr), 1))
 
-#ifdef WIN32
+#include <uv.h>
 
-#include <windows.h>
 
-#define sleep(secs) Sleep((secs) * 1000)
+class Network;
+class Options;
 
-enum {
-	PRIO_PROCESS		= 0,
+
+class App
+{
+public:
+  App(int argc, char **argv);
+  ~App();
+
+  int exec();
+
+private:
+  void background();
+  void close();
+
+  static void onSignal(uv_signal_t *handle, int signum);
+
+  static App *m_self;
+
+  Network *m_network;
+  Options *m_options;
+  uv_signal_t m_signal;
 };
 
-static inline int setpriority(int which, int who, int prio)
-{
-	return -!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
-}
 
-#endif /* WIN32 */
-
-#endif /* __COMPAT_H__ */
+#endif /* __APP_H__ */
diff --git a/src/App_unix.cpp b/src/App_unix.cpp
new file mode 100644
index 000000000..d001acb24
--- /dev/null
+++ b/src/App_unix.cpp
@@ -0,0 +1,66 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+
+
+#include "App.h"
+#include "Console.h"
+#include "Cpu.h"
+#include "Options.h"
+
+
+void App::background()
+{
+    if (m_options->affinity() != -1L) {
+        Cpu::setAffinity(-1, m_options->affinity());
+    }
+
+    if (!m_options->background()) {
+        return;
+    }
+
+    int i = fork();
+    if (i < 0) {
+        exit(1);
+    }
+
+    if (i > 0) {
+        exit(0);
+    }
+
+    i = setsid();
+
+    if (i < 0) {
+        LOG_ERR("setsid() failed (errno = %d)", errno);
+    }
+
+    i = chdir("/");
+    if (i < 0) {
+        LOG_ERR("chdir() failed (errno = %d)", errno);
+    }
+}
diff --git a/src/App_win.cpp b/src/App_win.cpp
new file mode 100644
index 000000000..895f3bdfc
--- /dev/null
+++ b/src/App_win.cpp
@@ -0,0 +1,52 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <winsock2.h>
+#include <windows.h>
+
+
+#include "App.h"
+#include "Options.h"
+#include "Cpu.h"
+
+
+void App::background()
+{
+    if (m_options->affinity() != -1L) {
+        Cpu::setAffinity(-1, m_options->affinity());
+    }
+
+    if (!m_options->background()) {
+        return;
+    }
+
+    HWND hcon = GetConsoleWindow();
+    if (hcon) {
+        ShowWindow(hcon, SW_HIDE);
+    } else {
+        HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+        CloseHandle(h);
+        FreeConsole();
+    }
+}
diff --git a/src/Console.cpp b/src/Console.cpp
new file mode 100644
index 000000000..2ce56ee19
--- /dev/null
+++ b/src/Console.cpp
@@ -0,0 +1,144 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+
+#ifdef WIN32
+#   include <winsock2.h>
+#   include "3rdparty/winansi.h"
+#endif
+
+#include "Console.h"
+
+
+Console *Console::m_self = nullptr;
+
+
+void Console::init()
+{
+    if (!m_self) {
+        m_self = new Console();
+    }
+}
+
+
+void Console::message(Console::Level level, const char* fmt, ...)
+{
+    time_t now = time(nullptr);
+    tm stime;
+
+#   ifdef _WIN32
+    localtime_s(&stime, &now);
+#   else
+    localtime_r(&now, &stime);
+#   endif
+
+    va_list ap;
+    va_start(ap, fmt);
+
+    const char* color = nullptr;
+    if (m_colors) {
+        switch (level) {
+        case ERR:
+            color = kCL_RED;
+            break;
+
+        case WARNING:
+            color = kCL_YELLOW;
+            break;
+
+        case NOTICE:
+            color = kCL_WHITE;
+            break;
+
+        case DEBUG:
+            color = kCL_GRAY;
+            break;
+
+        default:
+            color = "";
+            break;
+        }
+    }
+
+    const size_t len = 64 + strlen(fmt) + 2;
+    char *buf = static_cast<char *>(alloca(len));
+
+    sprintf(buf, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s\n",
+            stime.tm_year + 1900,
+            stime.tm_mon + 1,
+            stime.tm_mday,
+            stime.tm_hour,
+            stime.tm_min,
+            stime.tm_sec,
+            color,
+            fmt,
+            m_colors ? kCL_N : ""
+        );
+
+    uv_mutex_lock(&m_mutex);
+
+    vfprintf(stdout, buf, ap);
+    fflush(stdout);
+
+    uv_mutex_unlock(&m_mutex);
+
+    va_end(ap);
+}
+
+
+void Console::text(const char* fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+
+    const int len = 64 + strlen(fmt) + 2;
+    char *buf = static_cast<char *>(alloca(len));
+
+    sprintf(buf, "%s%s\n",
+            fmt,
+            m_colors ? kCL_N : ""
+        );
+
+    uv_mutex_lock(&m_mutex);
+
+    vfprintf(stdout, buf, ap);
+    fflush(stdout);
+
+    uv_mutex_unlock(&m_mutex);
+
+    va_end(ap);
+}
+
+
+Console::Console() :
+    m_colors(true)
+{
+    uv_mutex_init(&m_mutex);
+}
diff --git a/src/Console.h b/src/Console.h
new file mode 100644
index 000000000..73e047061
--- /dev/null
+++ b/src/Console.h
@@ -0,0 +1,83 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CONSOLE_H__
+#define __CONSOLE_H__
+
+
+#include <uv.h>
+
+
+class Console
+{
+public:
+    enum Level {
+        ERR,
+        WARNING,
+        NOTICE,
+        INFO,
+        DEBUG
+    };
+
+    constexpr static const char* kCL_N      = "\x1B[0m";
+    constexpr static const char* kCL_RED    = "\x1B[31m";
+    constexpr static const char* kCL_YELLOW = "\x1B[33m";
+    constexpr static const char* kCL_WHITE  = "\x1B[01;37m";
+
+#   ifdef WIN32
+    constexpr static const char* kCL_GRAY = "\x1B[01;30m";
+#   else
+    constexpr static const char* kCL_GRAY = "\x1B[90m";
+#   endif
+
+    static inline Console* i() { return m_self; }
+    static void init();
+
+    void message(Level level, const char* fmt, ...);
+    void text(const char* fmt, ...);
+
+private:
+    Console();
+
+    static Console *m_self;
+    bool m_colors;
+    uv_mutex_t m_mutex;
+};
+
+
+#define LOG_ERR(x, ...)    Console::i()->message(Console::ERR,     x, ##__VA_ARGS__)
+#define LOG_WARN(x, ...)   Console::i()->message(Console::WARNING, x, ##__VA_ARGS__)
+#define LOG_NOTICE(x, ...) Console::i()->message(Console::NOTICE,  x, ##__VA_ARGS__)
+#define LOG_INFO(x, ...)   Console::i()->message(Console::INFO,    x, ##__VA_ARGS__)
+
+#ifdef APP_DEBUG
+#   define LOG_DEBUG(x, ...)      Console::i()->message(Console::DEBUG,   x, ##__VA_ARGS__)
+#   define LOG_DEBUG_ERR(x, ...)  Console::i()->message(Console::ERR,     x, ##__VA_ARGS__)
+#   define LOG_DEBUG_WARN(x, ...) Console::i()->message(Console::WARNING, x, ##__VA_ARGS__)
+#else
+#   define LOG_DEBUG(x, ...)
+#   define LOG_DEBUG_ERR(x, ...)
+#   define LOG_DEBUG_WARN(x, ...)
+#endif
+
+#endif /* __CONSOLE_H__ */
diff --git a/cpu.c b/src/Cpu.cpp
similarity index 50%
rename from cpu.c
rename to src/Cpu.cpp
index bb8462389..2f0a11950 100644
--- a/cpu.c
+++ b/src/Cpu.cpp
@@ -21,73 +21,85 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <cpuid.h>
-#include <string.h>
-#include <stdbool.h>
+
+#include <libcpuid.h>
 #include <math.h>
+#include <string.h>
 
-#ifndef BUILD_TEST
-#   include <libcpuid.h>
-#endif
-
-#include "cpu.h"
-#include "utils/applog.h"
+#include "Cpu.h"
 
 
-#ifndef BUILD_TEST
-void cpu_init_common() {
+char Cpu::m_brand[64]   = { 0 };
+int Cpu::m_flags        = 0;
+int Cpu::m_l2_cache     = 0;
+int Cpu::m_l3_cache     = 0;
+int Cpu::m_sockets      = 1;
+int Cpu::m_totalCores   = 0;
+int Cpu::m_totalThreads = 0;
+
+
+int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
+{
+    if (m_totalThreads == 1) {
+        return 1;
+    }
+
+    int cache = m_l3_cache ? m_l3_cache : m_l2_cache;
+    int count = 0;
+    const int size = (algo ? 1024 : 2048) * (doubleHash ? 2 : 1);
+
+    if (cache) {
+        count = cache / size;
+    }
+    else {
+        count = m_totalThreads / 2;
+    }
+
+    if (count > m_totalThreads) {
+        count = m_totalThreads;
+    }
+
+    if (((float) count / m_totalThreads * 100) > maxCpuUsage) {
+        count = ceil((float) m_totalThreads * (maxCpuUsage / 100.0));
+    }
+
+    return count < 1 ? 1 : count;
+}
+
+
+void Cpu::initCommon()
+{
     struct cpu_raw_data_t raw = { 0 };
     struct cpu_id_t data = { 0 };
 
     cpuid_get_raw_data(&raw);
     cpu_identify(&raw, &data);
 
-    strncpy(cpu_info.brand, data.brand_str, sizeof(cpu_info.brand) - 1);
+    strncpy(m_brand, data.brand_str, sizeof(m_brand) - 1);
 
-    cpu_info.total_logical_cpus = data.total_logical_cpus;
-    cpu_info.sockets            = data.total_logical_cpus / data.num_logical_cpus;
-    cpu_info.total_cores        = data.num_cores * cpu_info.sockets;
-    cpu_info.l2_cache           = data.l2_cache > 0 ? data.l2_cache * cpu_info.total_cores * cpu_info.sockets : 0;
-    cpu_info.l3_cache           = data.l3_cache > 0 ? data.l3_cache * cpu_info.sockets : 0;
+    m_totalThreads = data.total_logical_cpus;
+    m_sockets = m_totalThreads / data.num_logical_cpus;
+    m_totalCores = data.num_cores *m_sockets;
 
-#   ifdef __x86_64__
-    cpu_info.flags |= CPU_FLAG_X86_64;
+    m_l3_cache = data.l3_cache > 0 ? data.l3_cache * m_sockets : 0;
+
+    // Workaround for AMD CPUs https://github.com/anrieff/libcpuid/issues/97
+    if (data.vendor == VENDOR_AMD && data.l3_cache <= 0 && data.l2_assoc == 16 && data.ext_family >= 21) {
+        m_l2_cache = data.l2_cache * (m_totalCores / 2) * m_sockets;
+    }
+    else {
+        m_l2_cache = data.l2_cache > 0 ? data.l2_cache * m_totalCores * m_sockets : 0;
+    }
+
+#   if defined(__x86_64__) || defined(_M_AMD64)
+    m_flags |= X86_64;
 #   endif
 
     if (data.flags[CPU_FEATURE_AES]) {
-        cpu_info.flags |= CPU_FLAG_AES;
+        m_flags |= AES;
     }
 
     if (data.flags[CPU_FEATURE_BMI2]) {
-        cpu_info.flags |= CPU_FLAG_BMI2;
+        m_flags |= BMI2;
     }
 }
-#endif
-
-
-int get_optimal_threads_count(int algo, bool double_hash, int max_cpu_usage) {
-    if (cpu_info.total_logical_cpus == 1) {
-        return 1;
-    }
-
-    int cache = cpu_info.l3_cache ? cpu_info.l3_cache : cpu_info.l2_cache;
-    int count = 0;
-    const int size = (algo ? 1024 : 2048) * (double_hash ? 2 : 1);
-
-    if (cache) {
-        count = cache / size;
-    }
-    else {
-        count = cpu_info.total_logical_cpus / 2;
-    }
-
-    if (count > cpu_info.total_logical_cpus) {
-        count = cpu_info.total_logical_cpus;
-    }
-
-    if (((float) count / cpu_info.total_logical_cpus * 100) > max_cpu_usage) {
-        count = ceil((float) cpu_info.total_logical_cpus * (max_cpu_usage / 100.0));
-    }
-
-    return count < 1 ? 1 : count;
-}
diff --git a/src/Cpu.h b/src/Cpu.h
new file mode 100644
index 000000000..292c6c6c3
--- /dev/null
+++ b/src/Cpu.h
@@ -0,0 +1,63 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CPU_H__
+#define __CPU_H__
+
+
+class Cpu
+{
+public:
+    enum Flags {
+        X86_64 = 1,
+        AES    = 2,
+        BMI2   = 4
+    };
+
+    static int optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage);
+    static void init();
+    static void setAffinity(int id, unsigned long mask);
+
+    static inline bool hasAES()       { return m_flags & AES; }
+    static inline bool isX64()        { return m_flags & X86_64; }
+    static inline const char *brand() { return m_brand; }
+    static inline int cores()         { return m_totalCores; }
+    static inline int l2()            { return m_l2_cache; }
+    static inline int l3()            { return m_l3_cache; }
+    static inline int sockets()       { return m_sockets; }
+    static inline int threads()       { return m_totalThreads; }
+
+private:
+    static void initCommon();
+
+    static char m_brand[64];
+    static int m_flags;
+    static int m_l2_cache;
+    static int m_l3_cache;
+    static int m_sockets;
+    static int m_totalCores;
+    static int m_totalThreads;
+};
+
+
+#endif /* __CPU_H__ */
diff --git a/stats.h b/src/Cpu_mac.cpp
similarity index 77%
rename from stats.h
rename to src/Cpu_mac.cpp
index 13ec117eb..3b6c44001 100644
--- a/stats.h
+++ b/src/Cpu_mac.cpp
@@ -21,17 +21,25 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __STATS_H__
-#define __STATS_H__
 
-#include <stdbool.h>
-#include <inttypes.h>
+#include <pthread.h>
+#include <sched.h>
+#include <unistd.h>
 
 
-void stats_init();
-void stats_set_target(uint32_t new_target);
-void stats_share_result(bool success);
-void stats_add_hashes(int thr_id, struct timeval *tv_start, unsigned long hashes_done);
+#include "Cpu.h"
 
 
-#endif /* __STATS_H__ */
+void Cpu::init()
+{
+#   ifdef XMRIG_NO_LIBCPUID
+    m_totalThreads = sysconf(_SC_NPROCESSORS_CONF);
+#   endif
+
+    initCommon();
+}
+
+
+void Cpu::setAffinity(int id, unsigned long mask)
+{
+}
diff --git a/cpu_stub.c b/src/Cpu_stub.cpp
similarity index 72%
rename from cpu_stub.c
rename to src/Cpu_stub.cpp
index 83d5efc36..0b9196eea 100644
--- a/cpu_stub.c
+++ b/src/Cpu_stub.cpp
@@ -21,10 +21,20 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <cpuid.h>
+
+#ifdef _MSC_VER
+#   include <intrin.h>
+
+#   define bit_AES  (1 << 25)
+#   define bit_BMI2 (1 << 8)
+#else
+#   include <cpuid.h>
+#endif
+
 #include <string.h>
-#include <stdbool.h>
-#include "cpu.h"
+
+
+#include "Cpu.h"
 
 
 #define VENDOR_ID                  (0)
@@ -41,6 +51,11 @@
 #define EDX_Reg  (3)
 
 
+#ifdef _MSC_VER
+static inline void cpuid(int level, int output[4]) {
+    __cpuid(output, level);
+}
+#else
 static inline void cpuid(int level, int output[4]) {
     int a, b, c, d;
     __cpuid_count(level, 0, a, b, c, d);
@@ -50,9 +65,10 @@ static inline void cpuid(int level, int output[4]) {
     output[2] = c;
     output[3] = d;
 }
+#endif
 
 
-static void cpu_brand_string(char* s) {
+static inline void cpu_brand_string(char* s) {
     int cpu_info[4] = { 0 };
     cpuid(VENDOR_ID, cpu_info);
 
@@ -66,7 +82,7 @@ static void cpu_brand_string(char* s) {
 }
 
 
-static bool has_aes_ni()
+static inline bool has_aes_ni()
 {
     int cpu_info[4] = { 0 };
     cpuid(PROCESSOR_INFO, cpu_info);
@@ -75,7 +91,7 @@ static bool has_aes_ni()
 }
 
 
-static bool has_bmi2() {
+static inline bool has_bmi2() {
     int cpu_info[4] = { 0 };
     cpuid(EXTENDED_FEATURES, cpu_info);
 
@@ -83,25 +99,35 @@ static bool has_bmi2() {
 }
 
 
-void cpu_init_common() {
-    cpu_info.sockets = 1;
-    cpu_brand_string(cpu_info.brand);
+char Cpu::m_brand[64]   = { 0 };
+int Cpu::m_flags        = 0;
+int Cpu::m_l2_cache     = 0;
+int Cpu::m_l3_cache     = 0;
+int Cpu::m_sockets      = 1;
+int Cpu::m_totalCores   = 0;
+int Cpu::m_totalThreads = 0;
 
-#   ifdef __x86_64__
-    cpu_info.flags |= CPU_FLAG_X86_64;
+
+int Cpu::optimalThreadsCount(int algo, bool doubleHash, int maxCpuUsage)
+{
+    int count = m_totalThreads / 2;
+    return count < 1 ? 1 : count;
+}
+
+
+void Cpu::initCommon()
+{
+    cpu_brand_string(m_brand);
+
+#   if defined(__x86_64__) || defined(_M_AMD64)
+    m_flags |= X86_64;
 #   endif
 
     if (has_aes_ni()) {
-        cpu_info.flags |= CPU_FLAG_AES;
+        m_flags |= AES;
     }
 
     if (has_bmi2()) {
-        cpu_info.flags |= CPU_FLAG_BMI2;
+        m_flags |= BMI2;
     }
 }
-
-
-int get_optimal_threads_count(int algo, bool double_hash, int max_cpu_usage) {
-    int count = cpu_info.total_logical_cpus / 2;
-    return count < 1 ? 1 : count;
-}
diff --git a/unix/cpu_unix.c b/src/Cpu_unix.cpp
similarity index 82%
rename from unix/cpu_unix.c
rename to src/Cpu_unix.cpp
index 05b859b22..1b7c6b0a8 100644
--- a/unix/cpu_unix.c
+++ b/src/Cpu_unix.cpp
@@ -21,32 +21,31 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <unistd.h>
-#include <sched.h>
+
 #include <pthread.h>
-
-#include "cpu.h"
+#include <sched.h>
+#include <unistd.h>
 
 
-struct cpu_info cpu_info = { 0 };
-void cpu_init_common();
+#include "Cpu.h"
 
 
-void cpu_init() {
+void Cpu::init()
+{
 #   ifdef XMRIG_NO_LIBCPUID
-    cpu_info.total_logical_cpus = sysconf(_SC_NPROCESSORS_CONF);
+    m_totalThreads = sysconf(_SC_NPROCESSORS_CONF);
 #   endif
 
-    cpu_init_common();
+    initCommon();
 }
 
 
-int affine_to_cpu_mask(int id, unsigned long mask)
+void Cpu::setAffinity(int id, unsigned long mask)
 {
     cpu_set_t set;
     CPU_ZERO(&set);
 
-    for (unsigned i = 0; i < cpu_info.total_logical_cpus; i++) {
+    for (int i = 0; i < m_totalThreads; i++) {
         if (mask & (1UL << i)) {
             CPU_SET(i, &set);
         }
diff --git a/win/cpu_win.c b/src/Cpu_win.cpp
similarity index 84%
rename from win/cpu_win.c
rename to src/Cpu_win.cpp
index 6b5cc7fad..fe4ea0ba4 100644
--- a/win/cpu_win.c
+++ b/src/Cpu_win.cpp
@@ -21,29 +21,27 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+
 #include <windows.h>
-#include <stdbool.h>
-
-#include "cpu.h"
 
 
-struct cpu_info cpu_info = { 0 };
-void cpu_init_common();
+#include "Cpu.h"
 
 
-void cpu_init() {
+void Cpu::init()
+{
 #   ifdef XMRIG_NO_LIBCPUID
     SYSTEM_INFO sysinfo;
     GetSystemInfo(&sysinfo);
 
-    cpu_info.total_logical_cpus = sysinfo.dwNumberOfProcessors;
+    m_totalThreads = sysinfo.dwNumberOfProcessors;
 #   endif
 
-    cpu_init_common();
+    initCommon();
 }
 
 
-int affine_to_cpu_mask(int id, unsigned long mask)
+void Cpu::setAffinity(int id, unsigned long mask)
 {
     if (id == -1) {
         SetProcessAffinityMask(GetCurrentProcess(), mask);
diff --git a/memory.c b/src/Mem.cpp
similarity index 51%
rename from memory.c
rename to src/Mem.cpp
index 2032a2548..4437c6739 100644
--- a/memory.c
+++ b/src/Mem.cpp
@@ -21,38 +21,45 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <string.h>
 
-#include "persistent_memory.h"
-#include "algo/cryptonight/cryptonight.h"
-#include "options.h"
-
-static size_t offset = 0;
+#include <memory.h>
 
 
-#ifndef XMRIG_NO_AEON
-static void * create_persistent_ctx_lite(int thr_id) {
-    struct cryptonight_ctx *ctx = NULL;
+#include "crypto/CryptoNight.h"
+#include "Mem.h"
+#include "Options.h"
 
-    if (!opt_double_hash) {
-        const size_t offset = MEMORY * (thr_id + 1);
 
-        ctx = (struct cryptonight_ctx *) &persistent_memory[offset + MEMORY_LITE];
-        ctx->memory = &persistent_memory[offset];
-        return ctx;
+bool Mem::m_doubleHash = false;
+int Mem::m_algo        = 0;
+int Mem::m_flags       = 0;
+int Mem::m_threads     = 0;
+size_t Mem::m_offset   = 0;
+uint8_t *Mem::m_memory = nullptr;
+
+
+cryptonight_ctx *Mem::create(int threadId)
+{
+#   ifndef XMRIG_NO_AEON
+    if (m_algo == Options::ALGO_CRYPTONIGHT_LITE) {
+        return createLite(threadId);
     }
+#   endif
 
-    ctx = (struct cryptonight_ctx *) &persistent_memory[MEMORY - sizeof(struct cryptonight_ctx) * (thr_id + 1)];
-    ctx->memory = &persistent_memory[MEMORY * (thr_id + 1)];
+    cryptonight_ctx *ctx = reinterpret_cast<cryptonight_ctx *>(&m_memory[MEMORY - sizeof(cryptonight_ctx) * (threadId + 1)]);
+
+    const int ratio = m_doubleHash ? 2 : 1;
+    ctx->memory = &m_memory[MEMORY * (threadId * ratio + 1)];
 
     return ctx;
 }
-#endif
 
 
-void * persistent_calloc(size_t num, size_t size) {
-    void *mem = &persistent_memory[offset];
-    offset += (num * size);
+
+void *Mem::calloc(size_t num, size_t size)
+{
+    void *mem = &m_memory[m_offset];
+    m_offset += (num * size);
 
     memset(mem, 0, num * size);
 
@@ -60,17 +67,21 @@ void * persistent_calloc(size_t num, size_t size) {
 }
 
 
-void * create_persistent_ctx(int thr_id) {
-#   ifndef XMRIG_NO_AEON
-    if (opt_algo == ALGO_CRYPTONIGHT_LITE) {
-        return create_persistent_ctx_lite(thr_id);
+#ifndef XMRIG_NO_AEON
+cryptonight_ctx *Mem::createLite(int threadId) {
+    cryptonight_ctx *ctx;
+
+    if (!m_doubleHash) {
+        const size_t offset = MEMORY * (threadId + 1);
+
+        ctx = reinterpret_cast<cryptonight_ctx *>(&m_memory[offset + MEMORY_LITE]);
+        ctx->memory = &m_memory[offset];
+        return ctx;
     }
-#   endif
 
-    struct cryptonight_ctx *ctx = (struct cryptonight_ctx *) &persistent_memory[MEMORY - sizeof(struct cryptonight_ctx) * (thr_id + 1)];
-
-    const int ratio = opt_double_hash ? 2 : 1;
-    ctx->memory = &persistent_memory[MEMORY * (thr_id * ratio + 1)];
+    ctx = reinterpret_cast<cryptonight_ctx *>(&m_memory[MEMORY - sizeof(cryptonight_ctx) * (threadId + 1)]);
+    ctx->memory = &m_memory[MEMORY * (threadId + 1)];
 
     return ctx;
 }
+#endif
diff --git a/src/Mem.h b/src/Mem.h
new file mode 100644
index 000000000..4198d8a2a
--- /dev/null
+++ b/src/Mem.h
@@ -0,0 +1,71 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MEM_H__
+#define __MEM_H__
+
+
+#include <stdint.h>
+
+
+#include "align.h"
+
+
+struct cryptonight_ctx;
+
+
+class Mem
+{
+public:
+    enum Flags {
+        HugepagesAvailable = 1,
+        HugepagesEnabled   = 2,
+        Lock               = 4
+    };
+
+    static bool allocate(int algo, int threads, bool doubleHash);
+    static cryptonight_ctx *create(int threadId);
+    static void *calloc(size_t num, size_t size);
+    static void release();
+
+    static inline bool isDoubleHash()         { return m_doubleHash; }
+    static inline bool isHugepagesAvailable() { return m_flags & HugepagesAvailable; }
+    static inline bool isHugepagesEnabled()   { return m_flags & HugepagesEnabled; }
+    static inline int flags()                 { return m_flags; }
+    static inline int threads()               { return m_threads; }
+
+private:
+    static bool m_doubleHash;
+    static int m_algo;
+    static int m_flags;
+    static int m_threads;
+    static size_t m_offset;
+    VAR_ALIGN(16, static uint8_t *m_memory);
+
+#   ifndef XMRIG_NO_AEON
+    static cryptonight_ctx *createLite(int threadId);
+#   endif
+};
+
+
+#endif /* __MEM_H__ */
diff --git a/src/Mem_unix.cpp b/src/Mem_unix.cpp
new file mode 100644
index 000000000..eb3f9af64
--- /dev/null
+++ b/src/Mem_unix.cpp
@@ -0,0 +1,86 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+#include <mm_malloc.h>
+#include <sys/mman.h>
+
+
+#include "crypto/CryptoNight.h"
+#include "Mem.h"
+#include "Options.h"
+#include "Console.h"
+
+
+bool Mem::allocate(int algo, int threads, bool doubleHash)
+{
+    m_algo       = algo;
+    m_threads    = threads;
+    m_doubleHash = doubleHash;
+
+    const int ratio   = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
+    const size_t size = MEMORY * (threads * ratio + 1);
+
+    m_flags |= HugepagesAvailable;
+
+#   if defined(__APPLE__)
+    m_memory = static_cast<uint8_t*>(mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0));
+#   else
+    m_memory = static_cast<uint8_t*>(mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0));
+#   endif
+
+    if (m_memory == MAP_FAILED) {
+        m_memory = static_cast<uint8_t*>(_mm_malloc(size, 16));
+        return true;
+    }
+
+    m_flags |= HugepagesEnabled;
+
+    if (madvise(m_memory, size, MADV_RANDOM | MADV_WILLNEED) != 0) {
+        LOG_ERR("madvise failed");
+    }
+
+    if (mlock(m_memory, size) == 0) {
+        m_flags |= Lock;
+    }
+
+    return true;
+}
+
+
+void Mem::release()
+{
+    const int size = MEMORY * (m_threads + 1);
+
+    if (m_flags & HugepagesEnabled) {
+        if (m_flags & Lock) {
+            munlock(m_memory, size);
+        }
+
+        munmap(m_memory, size);
+    }
+    else {
+        _mm_free(m_memory);
+    }
+}
diff --git a/win/memory_win.c b/src/Mem_win.cpp
similarity index 79%
rename from win/memory_win.c
rename to src/Mem_win.cpp
index 9ff63dade..c5e606f77 100644
--- a/win/memory_win.c
+++ b/src/Mem_win.cpp
@@ -21,20 +21,22 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __MEMORY_H__
-#define __MEMORY_H__
 
+#include <winsock2.h>
 #include <windows.h>
 #include <ntsecapi.h>
 #include <tchar.h>
 
-#include "options.h"
-#include "persistent_memory.h"
-#include "utils/applog.h"
+#ifdef __GNUC__
+#   include <mm_malloc.h>
+#else
+#   include <malloc.h>
+#endif
 
-
-char *persistent_memory;
-int persistent_memory_flags = 0;
+#include "Console.h"
+#include "crypto/CryptoNight.h"
+#include "Mem.h"
+#include "Options.h"
 
 
 /*****************************************************************
@@ -122,7 +124,7 @@ static BOOL ObtainLockPagesPrivilege() {
         LSA_UNICODE_STRING str = StringToLsaUnicodeString(_T(SE_LOCK_MEMORY_NAME));
 
         if (LsaAddAccountRights(handle, user->User.Sid, &str, 1) == 0) {
-            applog_notime(LOG_WARNING, "Huge pages support was successfully enabled, but reboot required to use it");
+            LOG_DEBUG("Huge pages support was successfully enabled, but reboot required to use it");
             result = TRUE;
         }
 
@@ -143,33 +145,37 @@ static BOOL TrySetLockPagesPrivilege() {
 }
 
 
-const char * persistent_memory_allocate() {
-    const int ratio = (opt_double_hash && opt_algo != ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
-    const int size  = MEMORY * (opt_n_threads * ratio + 1);
+bool Mem::allocate(int algo, int threads, bool doubleHash)
+{
+    m_algo       = algo;
+    m_threads    = threads;
+    m_doubleHash = doubleHash;
+
+    const int ratio = (doubleHash && algo != Options::ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
+    const size_t size  = MEMORY * (threads * ratio + 1);
 
     if (TrySetLockPagesPrivilege()) {
-        persistent_memory_flags |= MEMORY_HUGEPAGES_AVAILABLE;
+        m_flags |= HugepagesAvailable;
     }
 
-    persistent_memory = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE);
-    if (!persistent_memory) {
-        persistent_memory = _mm_malloc(size, 16);
+    m_memory = static_cast<uint8_t*>(VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE));
+    if (!m_memory) {
+        m_memory = static_cast<uint8_t*>(_mm_malloc(size, 16));
     }
     else {
-        persistent_memory_flags |= MEMORY_HUGEPAGES_ENABLED;
+        m_flags |= HugepagesEnabled;
     }
 
-    return persistent_memory;
+    return true;
 }
 
 
-void persistent_memory_free() {
-    if (persistent_memory_flags & MEMORY_HUGEPAGES_ENABLED) {
-        VirtualFree(persistent_memory, 0, MEM_RELEASE);
+void Mem::release()
+{
+    if (m_flags & HugepagesEnabled) {
+        VirtualFree(m_memory, 0, MEM_RELEASE);
     }
     else {
-        _mm_free(persistent_memory);
+        _mm_free(m_memory);
     }
 }
-
-#endif /* __MEMORY_H__ */
diff --git a/src/Options.cpp b/src/Options.cpp
new file mode 100644
index 000000000..111543eca
--- /dev/null
+++ b/src/Options.cpp
@@ -0,0 +1,505 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <jansson.h>
+#include <string.h>
+#include <uv.h>
+
+
+#ifdef _MSC_VER
+#   include "getopt/getopt.h"
+#else
+#   include <getopt.h>
+#endif
+
+
+#include "Console.h"
+#include "Cpu.h"
+#include "donate.h"
+#include "net/Url.h"
+#include "Options.h"
+#include "version.h"
+
+
+#ifndef ARRAY_SIZE
+#   define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+
+Options *Options::m_self = nullptr;
+
+
+static char const usage[] = "\
+Usage: " APP_ID " [OPTIONS]\n\
+Options:\n\
+  -a, --algo=ALGO       cryptonight (default) or cryptonight-lite\n\
+  -o, --url=URL         URL of mining server\n\
+  -b, --backup-url=URL  URL of backup mining server\n\
+  -O, --userpass=U:P    username:password pair for mining server\n\
+  -u, --user=USERNAME   username for mining server\n\
+  -p, --pass=PASSWORD   password for mining server\n\
+  -t, --threads=N       number of miner threads\n\
+  -v, --av=N            algorithm variation, 0 auto select\n\
+  -k, --keepalive       send keepalived for prevent timeout (need pool support)\n\
+  -r, --retries=N       number of times to retry before switch to backup server (default: 5)\n\
+  -R, --retry-pause=N   time to pause between retries (default: 5)\n\
+      --cpu-affinity    set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\
+      --no-color        disable colored output\n\
+      --donate-level=N  donate level, default 5%% (5 minutes in 100 minutes)\n\
+  -B, --background      run the miner in the background\n\
+  -c, --config=FILE     load a JSON-format configuration file\n\
+      --max-cpu-usage=N maximum CPU usage for automatic threads mode (default 75)\n\
+      --safe            safe adjust threads and av settings for current CPU\n\
+      --nicehash        enable nicehash support\n\
+  -h, --help            display this help and exit\n\
+  -V, --version         output version information and exit\n\
+";
+
+
+static char const short_options[] = "a:c:khBp:Px:r:R:s:t:T:o:u:O:v:Vb:";
+
+
+static struct option const options[] = {
+    { "algo",          1, nullptr, 'a'  },
+    { "av",            1, nullptr, 'v'  },
+    { "background",    0, nullptr, 'B'  },
+    { "backup-url",    1, nullptr, 'b'  },
+    { "config",        1, nullptr, 'c'  },
+    { "cpu-affinity",  1, nullptr, 1020 },
+    { "donate-level",  1, nullptr, 1003 },
+    { "help",          0, nullptr, 'h'  },
+    { "keepalive",     0, nullptr ,'k'  },
+    { "max-cpu-usage", 1, nullptr, 1004 },
+    { "nicehash",      0, nullptr, 1006 },
+    { "no-color",      0, nullptr, 1002 },
+    { "pass",          1, nullptr, 'p'  },
+    { "retries",       1, nullptr, 'r'  },
+    { "retry-pause",   1, nullptr, 'R'  },
+    { "safe",          0, nullptr, 1005 },
+    { "threads",       1, nullptr, 't'  },
+    { "url",           1, nullptr, 'o'  },
+    { "user",          1, nullptr, 'u'  },
+    { "userpass",      1, nullptr, 'O'  },
+    { "version",       0, nullptr, 'V'  },
+    { 0, 0, 0, 0 }
+};
+
+
+static const char *algo_names[] = {
+    "cryptonight",
+#   ifndef XMRIG_NO_AEON
+    "cryptonight-lite"
+#   endif
+};
+
+
+Options *Options::parse(int argc, char **argv)
+{
+    if (!m_self) {
+        m_self = new Options(argc, argv);
+    }
+
+    return m_self;
+}
+
+
+const char *Options::algoName() const
+{
+    return algo_names[m_algo];
+}
+
+
+Options::Options(int argc, char **argv) :
+    m_background(false),
+    m_colors(true),
+    m_doubleHash(false),
+    m_keepAlive(false),
+    m_nicehash(false),
+    m_ready(false),
+    m_safe(false),
+    m_pass(nullptr),
+    m_user(nullptr),
+    m_algo(0),
+    m_algoVariant(0),
+    m_donateLevel(kDonateLevel),
+    m_maxCpuUsage(75),
+    m_retries(5),
+    m_retryPause(5),
+    m_threads(0),
+    m_affinity(-1L),
+    m_backupUrl(nullptr),
+    m_url(nullptr)
+{
+    int key;
+
+    while (1) {
+        key = getopt_long(argc, argv, short_options, options, NULL);
+        if (key < 0) {
+            break;
+        }
+
+        if (!parseArg(key, optarg)) {
+            return;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr, "%s: unsupported non-option argument '%s'\n", argv[0], argv[optind]);
+        return;
+    }
+
+    if (!m_url) {
+        LOG_ERR("No pool URL supplied. Exiting.", argv[0]);
+        return;
+    }
+
+    if (!m_nicehash && m_url->isNicehash()) {
+        m_nicehash = true;
+    }
+
+    if (!m_user) {
+        m_user = strdup("x");
+    }
+
+    if (!m_pass) {
+        m_pass = strdup("x");
+    }
+
+    m_algoVariant = getAlgoVariant();
+    if (m_algoVariant == AV2_AESNI_DOUBLE || m_algoVariant == AV4_SOFT_AES_DOUBLE) {
+        m_doubleHash = true;
+    }
+
+    if (!m_threads) {
+        m_threads = Cpu::optimalThreadsCount(m_algo, m_doubleHash, m_maxCpuUsage);
+    }
+    else if (m_safe) {
+        const int count = Cpu::optimalThreadsCount(m_algo, m_doubleHash, m_maxCpuUsage);
+        if (m_threads > count) {
+            m_threads = count;
+        }
+    }
+
+    m_ready = true;
+}
+
+
+Options::~Options()
+{
+    delete m_url;
+    delete m_backupUrl;
+
+    free(m_user);
+    free(m_pass);
+}
+
+
+bool Options::parseArg(int key, char *arg)
+{
+    char *p;
+    int v;
+    uint64_t ul;
+    Url *url;
+
+    switch (key) {
+    case 'a': /* --algo */
+        if (!setAlgo(arg)) {
+            return false;
+        }
+        break;
+
+    case 'O': /* --userpass */
+        if (!setUserpass(arg)) {
+            return false;
+        }
+        break;
+
+    case 'o': /* --url */
+        url = parseUrl(arg);
+        if (url) {
+            free(m_url);
+            m_url = url;
+        }
+        break;
+
+    case 'b': /* --backup-url */
+        url = parseUrl(arg);
+        if (url) {
+            free(m_backupUrl);
+            m_backupUrl = url;
+        }
+        break;
+
+    case 'u': /* --user */
+        free(m_user);
+        m_user = strdup(arg);
+        break;
+
+    case 'p': /* --pass */
+        free(m_pass);
+        m_pass = strdup(arg);
+        break;
+
+    case 'r': /* --retries */
+        v = strtol(arg, nullptr, 10);
+        if (v < 1 || v > 1000) {
+            showUsage(1);
+            return false;
+        }
+
+        m_retries = v;
+        break;
+
+    case 'R': /* --retry-pause */
+        v = strtol(arg, nullptr, 10);
+        if (v < 1 || v > 3600) {
+            showUsage(1);
+            return false;
+        }
+
+        m_retryPause = v;
+        break;
+
+    case 't': /* --threads */
+        v = strtol(arg, nullptr, 10);
+        if (v < 1 || v > 1024) {
+            showUsage(1);
+            return false;
+        }
+
+        m_threads = v;
+        break;
+
+    case 1004: /* --max-cpu-usage */
+        v = strtol(arg, nullptr, 10);
+        if (v < 1 || v > 100) {
+            showUsage(1);
+            return false;
+        }
+
+        m_maxCpuUsage = v;
+        break;
+
+    case 1005: /* --safe */
+        m_safe = true;
+        break;
+
+    case 'k': /* --keepalive */
+        m_keepAlive = true;
+        break;
+
+    case 'V': /* --version */
+        showVersion();
+        return false;
+
+    case 'h': /* --help */
+        showUsage(0);
+        return false;
+
+    case 'B': /* --background */
+        m_background = true;
+        m_colors = false;
+        break;
+
+    case 'v': /* --av */
+        v = strtol(arg, nullptr, 10);
+        if (v < 0 || v > 1000) {
+            showUsage(1);
+            return false;
+        }
+
+        m_algoVariant = v;
+        break;
+
+    case 1020: /* --cpu-affinity */
+        p  = strstr(arg, "0x");
+        ul = p ? strtoul(p, NULL, 16) : atol(arg);
+        if (ul > (1UL << Cpu::threads()) -1) {
+            ul = -1;
+        }
+
+        m_affinity = ul;
+        break;
+
+    case 1002: /* --no-color */
+        m_colors = false;
+        break;
+
+    case 1003: /* --donate-level */
+        v = strtol(arg, nullptr, 10);
+        if (v < 1 || v > 99) {
+            showUsage(1);
+            return false;
+        }
+
+        m_donateLevel = v;
+        break;
+
+    case 1006: /* --nicehash */
+        m_nicehash = true;
+        break;
+
+    default:
+        showUsage(1);
+        return false;
+    }
+
+    return true;
+}
+
+
+Url *Options::parseUrl(const char *arg) const
+{
+    auto url = new Url(arg);
+    if (!url->isValid()) {
+        delete url;
+        return nullptr;
+    }
+
+    return url;
+}
+
+
+void Options::showUsage(int status) const
+{
+    if (status) {
+        fprintf(stderr, "Try \"" APP_ID "\" --help' for more information.\n");
+    }
+    else {
+        printf(usage);
+    }
+}
+
+
+void Options::showVersion()
+{
+    printf(APP_NAME " " APP_VERSION "\n built on " __DATE__
+
+#   if defined(__clang__)
+    " with clang " __clang_version__);
+#   elif defined(__GNUC__)
+    " with GCC");
+    printf(" %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
+#   elif defined(_MSC_VER)
+    " with MSVC");
+    printf(" %d", MSVC_VERSION);
+#   else
+    );
+#   endif
+
+    printf("\n features:"
+#   if defined(__i386__) || defined(_M_IX86)
+    " i386"
+#   elif defined(__x86_64__) || defined(_M_AMD64)
+    " x86_64"
+#   endif
+
+#   if defined(__AES__) || defined(_MSC_VER)
+    " AES-NI"
+#   endif
+    "\n");
+
+    printf("\nlibuv/%s\n", uv_version_string());
+    printf("libjansson/%s\n", JANSSON_VERSION);
+}
+
+
+bool Options::setAlgo(const char *algo)
+{
+    for (size_t i = 0; i < ARRAY_SIZE(algo_names); i++) {
+        if (algo_names[i] && !strcmp(algo, algo_names[i])) {
+            m_algo = i;
+            break;
+        }
+
+#       ifndef XMRIG_NO_AEON
+        if (i == ARRAY_SIZE(algo_names) - 1 && !strcmp(algo, "cryptonight-light")) {
+            m_algo = ALGO_CRYPTONIGHT_LITE;
+            break;
+        }
+#       endif
+
+        if (i == ARRAY_SIZE(algo_names) - 1) {
+            showUsage(1);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
+bool Options::setUserpass(const char *userpass)
+{
+    const char *p = strchr(userpass, ':');
+    if (!p) {
+        showUsage(1);
+        return false;
+    }
+
+    free(m_user);
+    free(m_pass);
+
+    m_user = static_cast<char*>(calloc(p - userpass + 1, 1));
+    strncpy(m_user, userpass, p - userpass);
+    m_pass = strdup(p + 1);
+
+    return true;
+}
+
+
+int Options::getAlgoVariant() const
+{
+#   ifndef XMRIG_NO_AEON
+    if (m_algo == ALGO_CRYPTONIGHT_LITE) {
+        return getAlgoVariantLite();
+    }
+#   endif
+
+    if (m_algoVariant <= AV0_AUTO || m_algoVariant >= AV_MAX) {
+        return Cpu::hasAES() ? AV1_AESNI : AV3_SOFT_AES;
+    }
+
+    if (m_safe && !Cpu::hasAES() && m_algoVariant <= AV2_AESNI_DOUBLE) {
+        return m_algoVariant + 2;
+    }
+
+    return m_algoVariant;
+}
+
+
+#ifndef XMRIG_NO_AEON
+int Options::getAlgoVariantLite() const
+{
+    if (m_algoVariant <= AV0_AUTO || m_algoVariant >= AV_MAX) {
+        return Cpu::hasAES() ? AV2_AESNI_DOUBLE : AV4_SOFT_AES_DOUBLE;
+    }
+
+    if (m_safe && !Cpu::hasAES() && m_algoVariant <= AV2_AESNI_DOUBLE) {
+        return m_algoVariant + 2;
+    }
+
+    return m_algoVariant;
+}
+#endif
diff --git a/src/Options.h b/src/Options.h
new file mode 100644
index 000000000..d8d6e4ae5
--- /dev/null
+++ b/src/Options.h
@@ -0,0 +1,114 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OPTIONS_H__
+#define __OPTIONS_H__
+
+
+#include <stdint.h>
+
+
+class Url;
+
+
+class Options
+{
+public:
+    enum Algo {
+        ALGO_CRYPTONIGHT,      /* CryptoNight (Monero) */
+        ALGO_CRYPTONIGHT_LITE, /* CryptoNight-Lite (AEON) */
+    };
+
+    enum AlgoVariant {
+        AV0_AUTO,
+        AV1_AESNI,
+        AV2_AESNI_DOUBLE,
+        AV3_SOFT_AES,
+        AV4_SOFT_AES_DOUBLE,
+        AV_MAX
+    };
+
+    static inline Options* i() { return m_self; }
+    static Options *parse(int argc, char **argv);
+
+    inline bool background() const      { return m_background; }
+    inline bool colors() const          { return m_colors; }
+    inline bool doubleHash() const      { return m_doubleHash; }
+    inline bool isReady() const         { return m_ready; }
+    inline bool keepAlive() const       { return m_keepAlive; }
+    inline bool nicehash() const        { return m_nicehash; }
+    inline const char *pass() const     { return m_pass; }
+    inline const char *user() const     { return m_user; }
+    inline const Url *backupUrl() const { return m_backupUrl; }
+    inline const Url *url() const       { return m_url; }
+    inline int algo() const             { return m_algo; }
+    inline int algoVariant() const      { return m_algoVariant; }
+    inline int donateLevel() const      { return m_donateLevel; }
+    inline int retries() const          { return m_retries; }
+    inline int retryPause() const       { return m_retryPause; }
+    inline int threads() const          { return m_threads; }
+    inline int64_t affinity() const     { return m_affinity; }
+
+    const char *algoName() const;
+
+private:
+    Options(int argc, char **argv);
+    ~Options();
+
+    static Options *m_self;
+
+    bool parseArg(int key, char *arg);
+    Url *parseUrl(const char *arg) const;
+    void showUsage(int status) const;
+    void showVersion(void);
+
+    bool setAlgo(const char *algo);
+    bool setUserpass(const char *userpass);
+
+    int getAlgoVariant() const;
+#   ifndef XMRIG_NO_AEON
+    int getAlgoVariantLite() const;
+#   endif
+
+    bool m_background;
+    bool m_colors;
+    bool m_doubleHash;
+    bool m_keepAlive;
+    bool m_nicehash;
+    bool m_ready;
+    bool m_safe;
+    char *m_pass;
+    char *m_user;
+    int m_algo;
+    int m_algoVariant;
+    int m_donateLevel;
+    int m_maxCpuUsage;
+    int m_retries;
+    int m_retryPause;
+    int m_threads;
+    int64_t m_affinity;
+    Url *m_backupUrl;
+    Url *m_url;
+};
+
+#endif /* __OPTIONS_H__ */
diff --git a/src/Summary.cpp b/src/Summary.cpp
new file mode 100644
index 000000000..8db808933
--- /dev/null
+++ b/src/Summary.cpp
@@ -0,0 +1,130 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <uv.h>
+
+
+#include "Console.h"
+#include "Cpu.h"
+#include "Mem.h"
+#include "Options.h"
+#include "Summary.h"
+#include "version.h"
+
+
+static void print_versions()
+{
+    char buf[16];
+
+#   if defined(__clang__)
+    snprintf(buf, 16, " clang/%d.%d.%d", __clang_major__, __clang_minor__, __clang_patchlevel__);
+#   elif defined(__GNUC__)
+    snprintf(buf, 16, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
+#   elif defined(_MSC_VER)
+    snprintf(buf, 16, " MSVC/%d", MSVC_VERSION);
+#   else
+    buf[0] = '\0';
+#   endif
+
+
+    if (Options::i()->colors()) {
+        Console::i()->text("\x1B[01;32m * \x1B[01;37mVERSIONS:     \x1B[01;36mXMRig/%s\x1B[01;37m libuv/%s%s", APP_VERSION, uv_version_string(), buf);
+    } else {
+        Console::i()->text(" * VERSIONS:     XMRig/%s libuv/%s%s", APP_VERSION, uv_version_string(), buf);
+    }
+}
+
+
+static void print_memory() {
+    if (Options::i()->colors()) {
+        Console::i()->text("\x1B[01;32m * \x1B[01;37mHUGE PAGES:   %s, %s",
+                           Mem::isHugepagesAvailable() ? "\x1B[01;32mavailable" : "\x1B[01;31munavailable",
+                           Mem::isHugepagesEnabled() ? "\x1B[01;32menabled" : "\x1B[01;31mdisabled");
+    }
+    else {
+        Console::i()->text(" * HUGE PAGES:   %s, %s", Mem::isHugepagesAvailable() ? "available" : "unavailable", Mem::isHugepagesEnabled() ? "enabled" : "disabled");
+    }
+}
+
+
+static void print_cpu()
+{
+    if (Options::i()->colors()) {
+        Console::i()->text("\x1B[01;32m * \x1B[01;37mCPU:          %s (%d) %sx64 %sAES-NI",
+                           Cpu::brand(),
+                           Cpu::sockets(),
+                           Cpu::isX64() ? "\x1B[01;32m" : "\x1B[01;31m-",
+                           Cpu::hasAES() ? "\x1B[01;32m" : "\x1B[01;31m-");
+#       ifndef XMRIG_NO_LIBCPUID
+        Console::i()->text("\x1B[01;32m * \x1B[01;37mCPU L2/L3:    %.1f MB/%.1f MB", Cpu::l2() / 1024.0, Cpu::l3() / 1024.0);
+#       endif
+    }
+    else {
+        Console::i()->text(" * CPU:          %s (%d) %sx64 %sAES-NI", Cpu::brand(), Cpu::sockets(), Cpu::isX64() ? "" : "-", Cpu::hasAES() ? "" : "-");
+#       ifndef XMRIG_NO_LIBCPUID
+        Console::i()->text(" * CPU L2/L3:    %.1f MB/%.1f MB", Cpu::l2() / 1024.0, Cpu::l3() / 1024.0);
+#       endif
+    }
+}
+
+
+static void print_threads()
+{
+    char buf[32];
+    if (Options::i()->affinity() != -1L) {
+        snprintf(buf, 32, ", affinity=0x%llX", Options::i()->affinity());
+    }
+    else {
+        buf[0] = '\0';
+    }
+
+    if (Options::i()->colors()) {
+        Console::i()->text("\x1B[01;32m * \x1B[01;37mTHREADS:      \x1B[01;36m%d\x1B[01;37m, %s, av=%d, donate=%d%%%s%s",
+                           Options::i()->threads(),
+                           Options::i()->algoName(),
+                           Options::i()->algoVariant(),
+                           Options::i()->donateLevel(),
+                           Options::i()->nicehash() ? ", nicehash" : "", buf);
+    }
+    else {
+        Console::i()->text(" * THREADS:      %d, %s, av=%d, donate=%d%%%s%s",
+                           Options::i()->threads(),
+                           Options::i()->algoName(),
+                           Options::i()->algoVariant(),
+                           Options::i()->donateLevel(),
+                           Options::i()->nicehash() ? ", nicehash" : "", buf);
+    }
+}
+
+
+void Summary::print()
+{
+    print_versions();
+    print_memory();
+    print_cpu();
+    print_threads();
+}
+
+
+
diff --git a/utils/summary.h b/src/Summary.h
similarity index 95%
rename from utils/summary.h
rename to src/Summary.h
index 628c53044..3f64fd60c 100644
--- a/utils/summary.h
+++ b/src/Summary.h
@@ -24,6 +24,12 @@
 #ifndef __SUMMARY_H__
 #define __SUMMARY_H__
 
-void print_summary();
+
+class Summary
+{
+public:
+    static void print();
+};
+
 
 #endif /* __SUMMARY_H__ */
diff --git a/src/crypto/CryptoNight.cpp b/src/crypto/CryptoNight.cpp
new file mode 100644
index 000000000..a463c9f97
--- /dev/null
+++ b/src/crypto/CryptoNight.cpp
@@ -0,0 +1,144 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "crypto/CryptoNight.h"
+#include "crypto/CryptoNight_p.h"
+#include "crypto/CryptoNight_test.h"
+#include "net/Job.h"
+#include "net/JobResult.h"
+#include "Options.h"
+
+
+void (*cryptonight_hash_ctx)(const void *input, size_t size, void *output, cryptonight_ctx *ctx) = nullptr;
+
+
+static void cryptonight_av1_aesni(const void *input, size_t size, void *output, struct cryptonight_ctx *ctx) {
+    cryptonight_hash<0x80000, MEMORY, 0x1FFFF0, false>(input, size, output, ctx);
+}
+
+
+static void cryptonight_av2_aesni_double(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+    cryptonight_double_hash<0x80000, MEMORY, 0x1FFFF0, false>(input, size, output, ctx);
+}
+
+
+static void cryptonight_av3_softaes(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+    cryptonight_hash<0x80000, MEMORY, 0x1FFFF0, true>(input, size, output, ctx);
+}
+
+
+static void cryptonight_av4_softaes_double(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+    cryptonight_double_hash<0x80000, MEMORY, 0x1FFFF0, true>(input, size, output, ctx);
+}
+
+
+#ifndef XMRIG_NO_AEON
+static void cryptonight_lite_av1_aesni(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+    cryptonight_hash<0x40000, MEMORY_LITE, 0xFFFF0, false>(input, size, output, ctx);
+}
+
+
+static void cryptonight_lite_av2_aesni_double(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+    cryptonight_double_hash<0x40000, MEMORY_LITE, 0xFFFF0, false>(input, size, output, ctx);
+}
+
+
+static void cryptonight_lite_av3_softaes(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+    cryptonight_hash<0x40000, MEMORY_LITE, 0xFFFF0, true>(input, size, output, ctx);
+}
+
+
+static void cryptonight_lite_av4_softaes_double(const void *input, size_t size, void *output, cryptonight_ctx *ctx) {
+    cryptonight_double_hash<0x40000, MEMORY_LITE, 0xFFFF0, true>(input, size, output, ctx);
+}
+
+void (*cryptonight_variations[8])(const void *input, size_t size, void *output, cryptonight_ctx *ctx) = {
+            cryptonight_av1_aesni,
+            cryptonight_av2_aesni_double,
+            cryptonight_av3_softaes,
+            cryptonight_av4_softaes_double,
+            cryptonight_lite_av1_aesni,
+            cryptonight_lite_av2_aesni_double,
+            cryptonight_lite_av3_softaes,
+            cryptonight_lite_av4_softaes_double
+        };
+#else
+void (*cryptonight_variations[4])(const void *input, size_t size, void *output, cryptonight_ctx *ctx) = {
+            cryptonight_av1_aesni,
+            cryptonight_av2_aesni_double,
+            cryptonight_av3_softaes,
+            cryptonight_av4_softaes_double
+        };
+#endif
+
+
+bool CryptoNight::hash(const Job &job, JobResult &result, cryptonight_ctx *ctx)
+{
+    cryptonight_hash_ctx(job.blob(), job.size(), result.result, ctx);
+
+    return *reinterpret_cast<uint64_t*>(result.result + 24) < job.target();
+}
+
+
+bool CryptoNight::init(int algo, int variant)
+{
+    if (variant < 1 || variant > 4) {
+        return false;
+    }
+
+#   ifndef XMRIG_NO_AEON
+    const int index = algo == Options::ALGO_CRYPTONIGHT_LITE ? (variant + 3) : (variant - 1);
+#   else
+    const int index = variant - 1;
+#   endif
+
+    cryptonight_hash_ctx = cryptonight_variations[index];
+
+    return selfTest(algo);
+}
+
+
+void CryptoNight::hash(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx)
+{
+    cryptonight_hash_ctx(input, size, output, ctx);
+}
+
+
+bool CryptoNight::selfTest(int algo) {
+    if (cryptonight_hash_ctx == nullptr) {
+        return false;
+    }
+
+    char output[64];
+
+    struct cryptonight_ctx *ctx = (struct cryptonight_ctx*) _mm_malloc(sizeof(struct cryptonight_ctx), 16);
+    ctx->memory = (uint8_t *) _mm_malloc(MEMORY * 2, 16);
+
+    cryptonight_hash_ctx(test_input, 76, output, ctx);
+
+    _mm_free(ctx->memory);
+    _mm_free(ctx);
+
+    return memcmp(output, algo == Options::ALGO_CRYPTONIGHT_LITE ? test_output1 : test_output0, (Options::i()->doubleHash() ? 64 : 32)) == 0;
+}
diff --git a/algo/cryptonight/cryptonight.h b/src/crypto/CryptoNight.h
similarity index 64%
rename from algo/cryptonight/cryptonight.h
rename to src/crypto/CryptoNight.h
index 0b0170735..64fc0fd1a 100644
--- a/algo/cryptonight/cryptonight.h
+++ b/src/crypto/CryptoNight.h
@@ -24,24 +24,38 @@
 #ifndef __CRYPTONIGHT_H__
 #define __CRYPTONIGHT_H__
 
+
 #include <stddef.h>
 #include <stdint.h>
-#include <stdbool.h>
+
+
+#include "align.h"
+
 
 #define MEMORY      2097152 /* 2 MiB */
 #define MEMORY_LITE 1048576 /* 1 MiB */
 
+
 struct cryptonight_ctx {
-    uint8_t state0[200] __attribute__((aligned(16)));
-    uint8_t state1[200] __attribute__((aligned(16)));
-    uint8_t* memory     __attribute__((aligned(16)));
+    VAR_ALIGN(16, uint8_t state0[200]);
+    VAR_ALIGN(16, uint8_t state1[200]);
+    VAR_ALIGN(16, uint8_t* memory);
 };
 
 
-extern void (* const extra_hashes[4])(const void *, size_t, char *);
+class Job;
+class JobResult;
 
-bool cryptonight_init(int variant);
-int scanhash_cryptonight(int thr_id, uint32_t *hash, uint32_t *restrict blob, size_t blob_size, uint32_t target, uint32_t max_nonce, unsigned long *restrict hashes_done, struct cryptonight_ctx *restrict ctx);
-int scanhash_cryptonight_double(int thr_id, uint32_t *hash, uint8_t *restrict blob, size_t blob_size, uint32_t target, uint32_t max_nonce, unsigned long *restrict hashes_done, struct cryptonight_ctx *restrict ctx);
+
+class CryptoNight
+{
+public:
+    static bool hash(const Job &job, JobResult &result, cryptonight_ctx *ctx);
+    static bool init(int algo, int variant);
+    static void hash(const uint8_t *input, size_t size, uint8_t *output, cryptonight_ctx *ctx);
+
+private:
+    static bool selfTest(int algo);
+};
 
 #endif /* __CRYPTONIGHT_H__ */
diff --git a/src/crypto/CryptoNight_p.h b/src/crypto/CryptoNight_p.h
new file mode 100644
index 000000000..fa2fa93a8
--- /dev/null
+++ b/src/crypto/CryptoNight_p.h
@@ -0,0 +1,440 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CRYPTONIGHT_P_H__
+#define __CRYPTONIGHT_P_H__
+
+
+#ifdef __GNUC__
+#   include <x86intrin.h>
+#else
+#   include <intrin.h>
+#   define __restrict__ __restrict
+#endif
+
+
+#include "crypto/CryptoNight.h"
+
+
+extern "C"
+{
+#include "crypto/c_keccak.h"
+#include "crypto/c_groestl.h"
+#include "crypto/c_blake256.h"
+#include "crypto/c_jh.h"
+#include "crypto/c_skein.h"
+
+__m128i soft_aesenc(__m128i in, __m128i key);
+__m128i soft_aeskeygenassist(__m128i key, uint8_t rcon);
+}
+
+
+static inline void do_blake_hash(const void* input, size_t len, char* output) {
+    blake256_hash(reinterpret_cast<uint8_t*>(output), static_cast<const uint8_t*>(input), len);
+}
+
+
+static inline void do_groestl_hash(const void* input, size_t len, char* output) {
+    groestl(static_cast<const uint8_t*>(input), len * 8, reinterpret_cast<uint8_t*>(output));
+}
+
+
+static inline void do_jh_hash(const void* input, size_t len, char* output) {
+    jh_hash(32 * 8, static_cast<const uint8_t*>(input), 8 * len, reinterpret_cast<uint8_t*>(output));
+}
+
+
+static inline void do_skein_hash(const void* input, size_t len, char* output) {
+    skein_hash(8 * 32, static_cast<const uint8_t*>(input), 8 * len, reinterpret_cast<uint8_t*>(output));
+}
+
+
+void (* const extra_hashes[4])(const void *, size_t, char *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash};
+
+
+
+#if defined(__x86_64__) || defined(_M_AMD64)
+#   define EXTRACT64(X) _mm_cvtsi128_si64(X)
+
+#   ifdef __GNUC__
+static inline uint64_t __umul128(uint64_t a, uint64_t b, uint64_t* hi)
+{
+    unsigned __int128 r = (unsigned __int128) a * (unsigned __int128) b;
+    *hi = r >> 64;
+    return (uint64_t) r;
+}
+#   else
+    #define __umul128 _umul128
+#   endif
+#elif defined(__i386__) || defined(_M_IX86)
+#   define HI32(X) \
+    _mm_srli_si128((X), 4)
+
+
+#   define EXTRACT64(X) \
+    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(X) | \
+    ((uint64_t)(uint32_t)_mm_cvtsi128_si32(HI32(X)) << 32))
+
+static inline uint64_t __umul128(uint64_t multiplier, uint64_t multiplicand, uint64_t *product_hi) {
+    // multiplier   = ab = a * 2^32 + b
+    // multiplicand = cd = c * 2^32 + d
+    // ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
+    uint64_t a = multiplier >> 32;
+    uint64_t b = multiplier & 0xFFFFFFFF;
+    uint64_t c = multiplicand >> 32;
+    uint64_t d = multiplicand & 0xFFFFFFFF;
+
+    //uint64_t ac = a * c;
+    uint64_t ad = a * d;
+    //uint64_t bc = b * c;
+    uint64_t bd = b * d;
+
+    uint64_t adbc = ad + (b * c);
+    uint64_t adbc_carry = adbc < ad ? 1 : 0;
+
+    // multiplier * multiplicand = product_hi * 2^64 + product_lo
+    uint64_t product_lo = bd + (adbc << 32);
+    uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
+    *product_hi = (a * c) + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
+
+    return product_lo;
+}
+#endif
+
+
+// This will shift and xor tmp1 into itself as 4 32-bit vals such as
+// sl_xor(a1 a2 a3 a4) = a1 (a2^a1) (a3^a2^a1) (a4^a3^a2^a1)
+static inline __m128i sl_xor(__m128i tmp1)
+{
+    __m128i tmp4;
+    tmp4 = _mm_slli_si128(tmp1, 0x04);
+    tmp1 = _mm_xor_si128(tmp1, tmp4);
+    tmp4 = _mm_slli_si128(tmp4, 0x04);
+    tmp1 = _mm_xor_si128(tmp1, tmp4);
+    tmp4 = _mm_slli_si128(tmp4, 0x04);
+    tmp1 = _mm_xor_si128(tmp1, tmp4);
+    return tmp1;
+}
+
+
+template<uint8_t rcon>
+static inline void aes_genkey_sub(__m128i* xout0, __m128i* xout2)
+{
+    __m128i xout1 = _mm_aeskeygenassist_si128(*xout2, rcon);
+    xout1  = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
+    *xout0 = sl_xor(*xout0);
+    *xout0 = _mm_xor_si128(*xout0, xout1);
+    xout1  = _mm_aeskeygenassist_si128(*xout0, 0x00);
+    xout1  = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
+    *xout2 = sl_xor(*xout2);
+    *xout2 = _mm_xor_si128(*xout2, xout1);
+}
+
+
+static inline void soft_aes_genkey_sub(__m128i* xout0, __m128i* xout2, uint8_t rcon)
+{
+    __m128i xout1 = soft_aeskeygenassist(*xout2, rcon);
+    xout1  = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
+    *xout0 = sl_xor(*xout0);
+    *xout0 = _mm_xor_si128(*xout0, xout1);
+    xout1  = soft_aeskeygenassist(*xout0, 0x00);
+    xout1  = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
+    *xout2 = sl_xor(*xout2);
+    *xout2 = _mm_xor_si128(*xout2, xout1);
+}
+
+
+template<bool SOFT_AES>
+static inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3, __m128i* k4, __m128i* k5, __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
+{
+    __m128i xout0 = _mm_load_si128(memory);
+    __m128i xout2 = _mm_load_si128(memory +1 );
+    *k0 = xout0;
+    *k1 = xout2;
+
+    SOFT_AES ? soft_aes_genkey_sub(&xout0, &xout2, 0x01) : aes_genkey_sub<0x01>(&xout0, &xout2);
+    *k2 = xout0;
+    *k3 = xout2;
+
+    SOFT_AES ? soft_aes_genkey_sub(&xout0, &xout2, 0x02) : aes_genkey_sub<0x02>(&xout0, &xout2);
+    *k4 = xout0;
+    *k5 = xout2;
+
+    SOFT_AES ? soft_aes_genkey_sub(&xout0, &xout2, 0x04) : aes_genkey_sub<0x04>(&xout0, &xout2);
+    *k6 = xout0;
+    *k7 = xout2;
+
+    SOFT_AES ? soft_aes_genkey_sub(&xout0, &xout2, 0x08) : aes_genkey_sub<0x08>(&xout0, &xout2);
+    *k8 = xout0;
+    *k9 = xout2;
+}
+
+
+template<bool SOFT_AES>
+static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
+{
+    if (SOFT_AES) {
+        *x0 = soft_aesenc(*x0, key);
+        *x1 = soft_aesenc(*x1, key);
+        *x2 = soft_aesenc(*x2, key);
+        *x3 = soft_aesenc(*x3, key);
+        *x4 = soft_aesenc(*x4, key);
+        *x5 = soft_aesenc(*x5, key);
+        *x6 = soft_aesenc(*x6, key);
+        *x7 = soft_aesenc(*x7, key);
+    }
+    else {
+        *x0 = _mm_aesenc_si128(*x0, key);
+        *x1 = _mm_aesenc_si128(*x1, key);
+        *x2 = _mm_aesenc_si128(*x2, key);
+        *x3 = _mm_aesenc_si128(*x3, key);
+        *x4 = _mm_aesenc_si128(*x4, key);
+        *x5 = _mm_aesenc_si128(*x5, key);
+        *x6 = _mm_aesenc_si128(*x6, key);
+        *x7 = _mm_aesenc_si128(*x7, key);
+    }
+}
+
+
+template<size_t MEM, bool SOFT_AES>
+static inline void cn_explode_scratchpad(const __m128i *input, __m128i *output)
+{
+    __m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7;
+    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
+
+    aes_genkey<SOFT_AES>(input, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
+
+    xin0 = _mm_load_si128(input + 4);
+    xin1 = _mm_load_si128(input + 5);
+    xin2 = _mm_load_si128(input + 6);
+    xin3 = _mm_load_si128(input + 7);
+    xin4 = _mm_load_si128(input + 8);
+    xin5 = _mm_load_si128(input + 9);
+    xin6 = _mm_load_si128(input + 10);
+    xin7 = _mm_load_si128(input + 11);
+
+    for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8) {
+        aes_round<SOFT_AES>(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+        aes_round<SOFT_AES>(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+        aes_round<SOFT_AES>(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+        aes_round<SOFT_AES>(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+        aes_round<SOFT_AES>(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+        aes_round<SOFT_AES>(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+        aes_round<SOFT_AES>(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+        aes_round<SOFT_AES>(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+        aes_round<SOFT_AES>(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+        aes_round<SOFT_AES>(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
+
+        _mm_store_si128(output + i + 0, xin0);
+        _mm_store_si128(output + i + 1, xin1);
+        _mm_store_si128(output + i + 2, xin2);
+        _mm_store_si128(output + i + 3, xin3);
+        _mm_store_si128(output + i + 4, xin4);
+        _mm_store_si128(output + i + 5, xin5);
+        _mm_store_si128(output + i + 6, xin6);
+        _mm_store_si128(output + i + 7, xin7);
+    }
+}
+
+
+template<size_t MEM, bool SOFT_AES>
+static inline void cn_implode_scratchpad(const __m128i *input, __m128i *output)
+{
+    __m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7;
+    __m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
+
+    aes_genkey<SOFT_AES>(output + 2, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
+
+    xout0 = _mm_load_si128(output + 4);
+    xout1 = _mm_load_si128(output + 5);
+    xout2 = _mm_load_si128(output + 6);
+    xout3 = _mm_load_si128(output + 7);
+    xout4 = _mm_load_si128(output + 8);
+    xout5 = _mm_load_si128(output + 9);
+    xout6 = _mm_load_si128(output + 10);
+    xout7 = _mm_load_si128(output + 11);
+
+    for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8)
+    {
+        xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0);
+        xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1);
+        xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2);
+        xout3 = _mm_xor_si128(_mm_load_si128(input + i + 3), xout3);
+        xout4 = _mm_xor_si128(_mm_load_si128(input + i + 4), xout4);
+        xout5 = _mm_xor_si128(_mm_load_si128(input + i + 5), xout5);
+        xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6);
+        xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7);
+
+        aes_round<SOFT_AES>(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+        aes_round<SOFT_AES>(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+        aes_round<SOFT_AES>(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+        aes_round<SOFT_AES>(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+        aes_round<SOFT_AES>(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+        aes_round<SOFT_AES>(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+        aes_round<SOFT_AES>(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+        aes_round<SOFT_AES>(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+        aes_round<SOFT_AES>(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+        aes_round<SOFT_AES>(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
+    }
+
+    _mm_store_si128(output + 4, xout0);
+    _mm_store_si128(output + 5, xout1);
+    _mm_store_si128(output + 6, xout2);
+    _mm_store_si128(output + 7, xout3);
+    _mm_store_si128(output + 8, xout4);
+    _mm_store_si128(output + 9, xout5);
+    _mm_store_si128(output + 10, xout6);
+    _mm_store_si128(output + 11, xout7);
+}
+
+
+template<size_t ITERATIONS, size_t MEM, size_t MASK, bool SOFT_AES>
+inline void cryptonight_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, cryptonight_ctx *__restrict__ ctx)
+{
+    keccak(static_cast<const uint8_t*>(input), size, ctx->state0, 200);
+
+    cn_explode_scratchpad<MEM, SOFT_AES>((__m128i*) ctx->state0, (__m128i*) ctx->memory);
+
+    const uint8_t* l0 = ctx->memory;
+    uint64_t* h0 = reinterpret_cast<uint64_t*>(ctx->state0);
+
+    uint64_t al0 = h0[0] ^ h0[4];
+    uint64_t ah0 = h0[1] ^ h0[5];
+    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+
+    uint64_t idx0 = h0[0] ^ h0[4];
+
+    for (size_t i = 0; i < ITERATIONS; i++) {
+        __m128i cx;
+        cx = _mm_load_si128((__m128i *) &l0[idx0 & MASK]);
+        cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0));
+
+        _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx));
+        idx0 = EXTRACT64(cx);
+        bx0 = cx;
+
+        uint64_t hi, lo, cl, ch;
+        cl = ((uint64_t*) &l0[idx0 & MASK])[0];
+        ch = ((uint64_t*) &l0[idx0 & MASK])[1];
+        lo = __umul128(idx0, cl, &hi);
+
+        al0 += hi;
+        ah0 += lo;
+
+        ((uint64_t*)&l0[idx0 & MASK])[0] = al0;
+        ((uint64_t*)&l0[idx0 & MASK])[1] = ah0;
+
+        ah0 ^= ch;
+        al0 ^= cl;
+        idx0 = al0;
+    }
+
+    cn_implode_scratchpad<MEM, SOFT_AES>((__m128i*) ctx->memory, (__m128i*) ctx->state0);
+
+    keccakf(h0, 24);
+    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, static_cast<char*>(output));
+}
+
+
+template<size_t ITERATIONS, size_t MEM, size_t MASK, bool SOFT_AES>
+inline void cryptonight_double_hash(const void *__restrict__ input, size_t size, void *__restrict__ output, struct cryptonight_ctx *__restrict__ ctx)
+{
+    keccak((const uint8_t *) input,        size, ctx->state0, 200);
+    keccak((const uint8_t *) input + size, size, ctx->state1, 200);
+
+    const uint8_t* l0 = ctx->memory;
+    const uint8_t* l1 = ctx->memory + MEM;
+    uint64_t* h0 = reinterpret_cast<uint64_t*>(ctx->state0);
+    uint64_t* h1 = reinterpret_cast<uint64_t*>(ctx->state1);
+
+    cn_explode_scratchpad<MEM, SOFT_AES>((__m128i*) h0, (__m128i*) l0);
+    cn_explode_scratchpad<MEM, SOFT_AES>((__m128i*) h1, (__m128i*) l1);
+
+    uint64_t al0 = h0[0] ^ h0[4];
+    uint64_t al1 = h1[0] ^ h1[4];
+    uint64_t ah0 = h0[1] ^ h0[5];
+    uint64_t ah1 = h1[1] ^ h1[5];
+
+    __m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
+    __m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
+
+    uint64_t idx0 = h0[0] ^ h0[4];
+    uint64_t idx1 = h1[0] ^ h1[4];
+
+    for (size_t i = 0; i < ITERATIONS; i++) {
+        __m128i cx0 = _mm_load_si128((__m128i *) &l0[idx0 & MASK]);
+        __m128i cx1 = _mm_load_si128((__m128i *) &l1[idx1 & MASK]);
+
+        cx0 = _mm_aesenc_si128(cx0, _mm_set_epi64x(ah0, al0));
+        cx1 = _mm_aesenc_si128(cx1, _mm_set_epi64x(ah1, al1));
+
+        _mm_store_si128((__m128i *) &l0[idx0 & MASK], _mm_xor_si128(bx0, cx0));
+        _mm_store_si128((__m128i *) &l1[idx1 & MASK], _mm_xor_si128(bx1, cx1));
+
+        idx0 = EXTRACT64(cx0);
+        idx1 = EXTRACT64(cx1);
+
+        bx0 = cx0;
+        bx1 = cx1;
+
+        uint64_t hi, lo, cl, ch;
+        cl = ((uint64_t*) &l0[idx0 & MASK])[0];
+        ch = ((uint64_t*) &l0[idx0 & MASK])[1];
+        lo = __umul128(idx0, cl, &hi);
+
+        al0 += hi;
+        ah0 += lo;
+
+        ((uint64_t*) &l0[idx0 & MASK])[0] = al0;
+        ((uint64_t*) &l0[idx0 & MASK])[1] = ah0;
+
+        ah0 ^= ch;
+        al0 ^= cl;
+        idx0 = al0;
+
+        cl = ((uint64_t*) &l1[idx1 & MASK])[0];
+        ch = ((uint64_t*) &l1[idx1 & MASK])[1];
+        lo = __umul128(idx1, cl, &hi);
+
+        al1 += hi;
+        ah1 += lo;
+
+        ((uint64_t*) &l1[idx1 & MASK])[0] = al1;
+        ((uint64_t*) &l1[idx1 & MASK])[1] = ah1;
+
+        ah1 ^= ch;
+        al1 ^= cl;
+        idx1 = al1;
+    }
+
+    cn_implode_scratchpad<MEM, SOFT_AES>((__m128i*) l0, (__m128i*) h0);
+    cn_implode_scratchpad<MEM, SOFT_AES>((__m128i*) l1, (__m128i*) h1);
+
+    keccakf(h0, 24);
+    keccakf(h1, 24);
+
+    extra_hashes[ctx->state0[0] & 3](ctx->state0, 200, static_cast<char*>(output));
+    extra_hashes[ctx->state1[0] & 3](ctx->state1, 200, static_cast<char*>(output) + 32);
+}
+
+#endif /* __CRYPTONIGHT_P_H__ */
diff --git a/src/crypto/CryptoNight_test.h b/src/crypto/CryptoNight_test.h
new file mode 100644
index 000000000..b2985379b
--- /dev/null
+++ b/src/crypto/CryptoNight_test.h
@@ -0,0 +1,60 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CRYPTONIGHT_TEST_H__
+#define __CRYPTONIGHT_TEST_H__
+
+
+const static uint8_t test_input[152] = {
+    0x01, 0x00, 0xFB, 0x8E, 0x8A, 0xC8, 0x05, 0x89, 0x93, 0x23, 0x37, 0x1B, 0xB7, 0x90, 0xDB, 0x19,
+    0x21, 0x8A, 0xFD, 0x8D, 0xB8, 0xE3, 0x75, 0x5D, 0x8B, 0x90, 0xF3, 0x9B, 0x3D, 0x55, 0x06, 0xA9,
+    0xAB, 0xCE, 0x4F, 0xA9, 0x12, 0x24, 0x45, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x81, 0x46, 0xD4, 0x9F,
+    0xA9, 0x3E, 0xE7, 0x24, 0xDE, 0xB5, 0x7D, 0x12, 0xCB, 0xC6, 0xC6, 0xF3, 0xB9, 0x24, 0xD9, 0x46,
+    0x12, 0x7C, 0x7A, 0x97, 0x41, 0x8F, 0x93, 0x48, 0x82, 0x8F, 0x0F, 0x02,
+    0x03, 0x05, 0xA0, 0xDB, 0xD6, 0xBF, 0x05, 0xCF, 0x16, 0xE5, 0x03, 0xF3, 0xA6, 0x6F, 0x78, 0x00,
+    0x7C, 0xBF, 0x34, 0x14, 0x43, 0x32, 0xEC, 0xBF, 0xC2, 0x2E, 0xD9, 0x5C, 0x87, 0x00, 0x38, 0x3B,
+    0x30, 0x9A, 0xCE, 0x19, 0x23, 0xA0, 0x96, 0x4B, 0x00, 0x00, 0x00, 0x08, 0xBA, 0x93, 0x9A, 0x62,
+    0x72, 0x4C, 0x0D, 0x75, 0x81, 0xFC, 0xE5, 0x76, 0x1E, 0x9D, 0x8A, 0x0E, 0x6A, 0x1C, 0x3F, 0x92,
+    0x4F, 0xDD, 0x84, 0x93, 0xD1, 0x11, 0x56, 0x49, 0xC0, 0x5E, 0xB6, 0x01
+};
+
+
+const static uint8_t test_output0[64] = {
+    0x1B, 0x60, 0x6A, 0x3F, 0x4A, 0x07, 0xD6, 0x48, 0x9A, 0x1B, 0xCD, 0x07, 0x69, 0x7B, 0xD1, 0x66,
+    0x96, 0xB6, 0x1C, 0x8A, 0xE9, 0x82, 0xF6, 0x1A, 0x90, 0x16, 0x0F, 0x4E, 0x52, 0x82, 0x8A, 0x7F,
+    0x1A, 0x3F, 0xFB, 0xEE, 0x90, 0x9B, 0x42, 0x0D, 0x91, 0xF7, 0xBE, 0x6E, 0x5F, 0xB5, 0x6D, 0xB7,
+    0x1B, 0x31, 0x10, 0xD8, 0x86, 0x01, 0x1E, 0x87, 0x7E, 0xE5, 0x78, 0x6A, 0xFD, 0x08, 0x01, 0x00
+};
+
+
+#ifndef XMRIG_NO_AEON
+const static uint8_t test_output1[64] = {
+    0x28, 0xA2, 0x2B, 0xAD, 0x3F, 0x93, 0xD1, 0x40, 0x8F, 0xCA, 0x47, 0x2E, 0xB5, 0xAD, 0x1C, 0xBE,
+    0x75, 0xF2, 0x1D, 0x05, 0x3C, 0x8C, 0xE5, 0xB3, 0xAF, 0x10, 0x5A, 0x57, 0x71, 0x3E, 0x21, 0xDD,
+    0x36, 0x95, 0xB4, 0xB5, 0x3B, 0xB0, 0x03, 0x58, 0xB0, 0xAD, 0x38, 0xDC, 0x16, 0x0F, 0xEB, 0x9E,
+    0x00, 0x4E, 0xEC, 0xE0, 0x9B, 0x83, 0xA7, 0x2E, 0xF6, 0xBA, 0x98, 0x64, 0xD3, 0x51, 0x0C, 0x88,
+};
+#endif
+
+
+#endif /* __CRYPTONIGHT_TEST_H__ */
diff --git a/crypto/c_blake256.c b/src/crypto/c_blake256.c
similarity index 100%
rename from crypto/c_blake256.c
rename to src/crypto/c_blake256.c
diff --git a/crypto/c_blake256.h b/src/crypto/c_blake256.h
similarity index 100%
rename from crypto/c_blake256.h
rename to src/crypto/c_blake256.h
diff --git a/crypto/c_groestl.c b/src/crypto/c_groestl.c
similarity index 100%
rename from crypto/c_groestl.c
rename to src/crypto/c_groestl.c
diff --git a/crypto/c_groestl.h b/src/crypto/c_groestl.h
similarity index 100%
rename from crypto/c_groestl.h
rename to src/crypto/c_groestl.h
diff --git a/crypto/c_jh.c b/src/crypto/c_jh.c
similarity index 100%
rename from crypto/c_jh.c
rename to src/crypto/c_jh.c
diff --git a/crypto/c_jh.h b/src/crypto/c_jh.h
similarity index 100%
rename from crypto/c_jh.h
rename to src/crypto/c_jh.h
diff --git a/crypto/c_keccak.c b/src/crypto/c_keccak.c
similarity index 100%
rename from crypto/c_keccak.c
rename to src/crypto/c_keccak.c
diff --git a/crypto/c_keccak.h b/src/crypto/c_keccak.h
similarity index 100%
rename from crypto/c_keccak.h
rename to src/crypto/c_keccak.h
diff --git a/crypto/c_skein.c b/src/crypto/c_skein.c
similarity index 100%
rename from crypto/c_skein.c
rename to src/crypto/c_skein.c
diff --git a/crypto/c_skein.h b/src/crypto/c_skein.h
similarity index 100%
rename from crypto/c_skein.h
rename to src/crypto/c_skein.h
diff --git a/crypto/groestl_tables.h b/src/crypto/groestl_tables.h
similarity index 100%
rename from crypto/groestl_tables.h
rename to src/crypto/groestl_tables.h
diff --git a/crypto/hash.h b/src/crypto/hash.h
similarity index 100%
rename from crypto/hash.h
rename to src/crypto/hash.h
diff --git a/crypto/skein_port.h b/src/crypto/skein_port.h
similarity index 100%
rename from crypto/skein_port.h
rename to src/crypto/skein_port.h
diff --git a/crypto/soft_aes.c b/src/crypto/soft_aes.c
similarity index 100%
rename from crypto/soft_aes.c
rename to src/crypto/soft_aes.c
diff --git a/cpu.h b/src/donate.h
similarity index 57%
rename from cpu.h
rename to src/donate.h
index 419192bf8..3a0009486 100644
--- a/cpu.h
+++ b/src/donate.h
@@ -21,33 +21,23 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __CPU_H__
-#define __CPU_H__
-
-#include <stdbool.h>
-
-struct cpu_info {
-    int total_cores;
-    int total_logical_cpus;
-    int flags;
-    int sockets;
-    int l2_cache;
-    int l3_cache;
-    char brand[64];
-};
-
-extern struct cpu_info cpu_info;
+#ifndef __DONATE_H__
+#define __DONATE_H__
 
 
-enum cpu_flags {
-    CPU_FLAG_X86_64 = 1,
-    CPU_FLAG_AES    = 2,
-    CPU_FLAG_BMI2   = 4
-};
+/*
+ * Dev donation.
+ *
+ * Percentage of your hashing power that you want to donate to the developer, can be 0 if you don't want to do that.
+ * Example of how it works for the default setting of 1:
+ * You miner will mine into your usual pool for 99 minutes, then switch to the developer's pool for 1 minute.
+ * Switching is instant, and only happens after a successful connection, so you never loose any hashes.
+ *
+ * If you plan on changing this setting to 0 please consider making a one off donation to my wallet:
+ * XMR: 48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD
+ * BTC: 1P7ujsXeX7GxQwHNnJsRMgAdNkFZmNVqJT
+ */
+constexpr const int kDonateLevel = 5;
 
 
-void cpu_init();
-int get_optimal_threads_count(int algo, bool double_hash, int max_cpu_usage);
-int affine_to_cpu_mask(int id, unsigned long mask);
-
-#endif /* __CPU_H__ */
+#endif /* __DONATE_H__ */
diff --git a/src/interfaces/IClientListener.h b/src/interfaces/IClientListener.h
new file mode 100644
index 000000000..570190359
--- /dev/null
+++ b/src/interfaces/IClientListener.h
@@ -0,0 +1,44 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ICLIENTLISTENER_H__
+#define __ICLIENTLISTENER_H__
+
+
+class Client;
+class Job;
+
+
+class IClientListener
+{
+public:
+    virtual ~IClientListener() {}
+
+    virtual void onClose(Client *client, int failures)         = 0;
+    virtual void onJobReceived(Client *client, const Job &job) = 0;
+    virtual void onLoginCredentialsRequired(Client *client)    = 0;
+    virtual void onLoginSuccess(Client *client)                = 0;
+};
+
+
+#endif // __ICLIENTLISTENER_H__
diff --git a/src/interfaces/IJobResultListener.h b/src/interfaces/IJobResultListener.h
new file mode 100644
index 000000000..483a2062d
--- /dev/null
+++ b/src/interfaces/IJobResultListener.h
@@ -0,0 +1,41 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __IJOBRESULTLISTENER_H__
+#define __IJOBRESULTLISTENER_H__
+
+
+class Client;
+class JobResult;
+
+
+class IJobResultListener
+{
+public:
+    virtual ~IJobResultListener() {}
+
+    virtual void onJobResult(const JobResult &result) = 0;
+};
+
+
+#endif // __IJOBRESULTLISTENER_H__
diff --git a/src/interfaces/IWorker.h b/src/interfaces/IWorker.h
new file mode 100644
index 000000000..b9b6eb0a0
--- /dev/null
+++ b/src/interfaces/IWorker.h
@@ -0,0 +1,42 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __IWORKER_H__
+#define __IWORKER_H__
+
+
+#include <stdint.h>
+
+
+class IWorker
+{
+public:
+    virtual ~IWorker() {}
+
+    virtual uint64_t hashCount() const = 0;
+    virtual uint64_t timestamp() const = 0;
+    virtual void start()               = 0;
+};
+
+
+#endif // __IWORKER_H__
diff --git a/src/net/Client.cpp b/src/net/Client.cpp
new file mode 100644
index 000000000..eb776da14
--- /dev/null
+++ b/src/net/Client.cpp
@@ -0,0 +1,498 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <utility>
+
+
+#include "Console.h"
+#include "interfaces/IClientListener.h"
+#include "net/Client.h"
+#include "net/JobResult.h"
+#include "net/Url.h"
+
+
+Client::Client(int id, IClientListener *listener) :
+    m_keepAlive(false),
+    m_host(nullptr),
+    m_listener(listener),
+    m_id(id),
+    m_retryPause(5000),
+    m_failures(0),
+    m_sequence(1),
+    m_recvBufPos(0),
+    m_state(UnconnectedState),
+    m_port(0),
+    m_stream(nullptr),
+    m_socket(nullptr)
+{
+    m_resolver.data = m_responseTimer.data = m_retriesTimer.data = m_keepAliveTimer.data = this;
+
+    m_hints.ai_family   = PF_INET;
+    m_hints.ai_socktype = SOCK_STREAM;
+    m_hints.ai_protocol = IPPROTO_TCP;
+    m_hints.ai_flags    = 0;
+
+    m_recvBuf.base = static_cast<char*>(malloc(kRecvBufSize));
+    m_recvBuf.len  = kRecvBufSize;
+
+    auto loop = uv_default_loop();
+    uv_timer_init(loop, &m_retriesTimer);
+    uv_timer_init(loop, &m_responseTimer);
+    uv_timer_init(loop, &m_keepAliveTimer);
+}
+
+
+Client::~Client()
+{
+    free(m_recvBuf.base);
+    free(m_socket);
+    free(m_host);
+}
+
+
+void Client::connect()
+{
+    resolve(m_host);
+}
+
+
+/**
+ * @brief Connect to server.
+ *
+ * @param url
+ */
+void Client::connect(const Url *url)
+{
+    setUrl(url);
+    resolve(m_host);
+}
+
+
+void Client::disconnect()
+{
+    m_failures = -1;
+
+    close();
+}
+
+
+void Client::login(const char *user, const char *pass, const char *agent)
+{
+    m_sequence = 1;
+
+    const size_t size = 96 + strlen(user) + strlen(pass) + strlen(agent);
+    char *req = static_cast<char*>(malloc(size));
+    snprintf(req, size, "{\"id\":%llu,\"jsonrpc\":\"2.0\",\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"%s\"}}\n", m_sequence, user, pass, agent);
+
+    send(req);
+}
+
+
+/**
+ * @brief Send raw data to server.
+ *
+ * @param data
+ */
+void Client::send(char *data)
+{
+    LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_host, m_port, strlen(data), data);
+    if (state() != ConnectedState) {
+        LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_host, m_port, m_state);
+        return;
+    }
+
+    m_sequence++;
+    uv_buf_t buf = uv_buf_init(data, strlen(data));
+
+    uv_write_t *req = static_cast<uv_write_t*>(malloc(sizeof(uv_write_t)));
+    req->data = buf.base;
+
+    uv_write(req, m_stream, &buf, 1, [](uv_write_t *req, int status) {
+        free(req->data);
+        free(req);
+    });
+
+    uv_timer_start(&m_responseTimer, [](uv_timer_t *handle) { getClient(handle->data)->close(); }, kResponseTimeout, 0);
+}
+
+
+void Client::setUrl(const Url *url)
+{
+    if (!url || !url->isValid()) {
+        return;
+    }
+
+    free(m_host);
+    m_host = strdup(url->host());
+    m_port = url->port();
+}
+
+
+void Client::submit(const JobResult &result)
+{
+    char *req = static_cast<char*>(malloc(345));
+    char nonce[9];
+    char data[65];
+
+    Job::toHex(reinterpret_cast<const unsigned char*>(&result.nonce), 4, nonce);
+    nonce[8] = '\0';
+
+    Job::toHex(result.result, 32, data);
+    data[64] = '\0';
+
+    snprintf(req, 345, "{\"id\":%llu,\"jsonrpc\":\"2.0\",\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"}}\n",
+             m_sequence, m_rpcId, result.jobId, nonce, data);
+
+    send(req);
+}
+
+
+bool Client::parseJob(const json_t *params, int *code)
+{
+    if (!json_is_object(params)) {
+        *code = 2;
+        return false;
+    }
+
+    Job job;
+    if (!job.setId(json_string_value(json_object_get(params, "job_id")))) {
+        *code = 3;
+        return false;
+    }
+
+    if (!job.setBlob(json_string_value(json_object_get(params, "blob")))) {
+        *code = 4;
+        return false;
+    }
+
+    if (!job.setTarget(json_string_value(json_object_get(params, "target")))) {
+        *code = 5;
+        return false;
+    }
+
+    job.setPoolId(m_id);
+    m_job = std::move(job);
+
+    LOG_DEBUG("[%s:%u] job: \"%s\", diff: %lld", m_host, m_port, job.id(), job.diff());
+    return true;
+}
+
+
+bool Client::parseLogin(const json_t *result, int *code)
+{
+    const char *id = json_string_value(json_object_get(result, "id"));
+    if (!id || strlen(id) >= sizeof(m_rpcId)) {
+        *code = 1;
+        return false;
+    }
+
+    memset(m_rpcId, 0, sizeof(m_rpcId));
+    memcpy(m_rpcId, id, strlen(id));
+
+    return parseJob(json_object_get(result, "job"), code);
+}
+
+
+int Client::resolve(const char *host)
+{
+    setState(HostLookupState);
+
+    m_recvBufPos = 0;
+
+    const int r = uv_getaddrinfo(uv_default_loop(), &m_resolver, Client::onResolved, host, NULL, &m_hints);
+    if (r) {
+        LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_port, uv_strerror(r));
+        return 1;
+    }
+
+    return 0;
+}
+
+
+void Client::close()
+{
+    if (m_state == UnconnectedState || m_state == ClosingState || !m_socket) {
+        return;
+    }
+
+    setState(ClosingState);
+    uv_close(reinterpret_cast<uv_handle_t*>(m_socket), Client::onClose);
+}
+
+
+void Client::connect(struct sockaddr *addr)
+{
+    setState(ConnectingState);
+
+    reinterpret_cast<struct sockaddr_in*>(addr)->sin_port = htons(m_port);
+    free(m_socket);
+
+    uv_connect_t *req = (uv_connect_t*) malloc(sizeof(uv_connect_t));
+    req->data = this;
+
+    m_socket = static_cast<uv_tcp_t*>(malloc(sizeof(uv_tcp_t)));
+    m_socket->data = this;
+
+    uv_tcp_init(uv_default_loop(), m_socket);
+    uv_tcp_nodelay(m_socket, 1);
+    uv_tcp_keepalive(m_socket, 1, 60);
+
+    uv_tcp_connect(req, m_socket, (const sockaddr*) addr, Client::onConnect);
+}
+
+
+void Client::parse(char *line, size_t len)
+{
+    startTimeout();
+
+    line[len - 1] = '\0';
+
+    LOG_DEBUG("[%s:%u] received (%d bytes): \"%s\"", m_host, m_port, len, line);
+
+    json_error_t err;
+    json_t *val = json_loads(line, 0, &err);
+
+    if (!val) {
+        LOG_ERR("[%s:%u] JSON decode failed: \"%s\"", m_host, m_port, err.text);
+        return;
+    }
+
+    const json_t *id = json_object_get(val, "id");
+    if (json_is_integer(id)) {
+        parseResponse(json_integer_value(id), json_object_get(val, "result"), json_object_get(val, "error"));
+    }
+    else {
+        parseNotification(json_string_value(json_object_get(val, "method")), json_object_get(val, "params"), json_object_get(val, "error"));
+    }
+
+    json_decref(val);
+}
+
+
+void Client::parseNotification(const char *method, const json_t *params, const json_t *error)
+{
+    if (json_is_object(error)) {
+        LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_host, m_port, json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code")));
+        return;
+    }
+
+    if (!method) {
+        return;
+    }
+
+    if (strcmp(method, "job") == 0) {
+        int code = -1;
+        if (parseJob(params, &code)) {
+            m_listener->onJobReceived(this, m_job);
+        }
+
+        return;
+    }
+
+    LOG_WARN("[%s:%u] unsupported method: \"%s\"", m_host, m_port, method);
+}
+
+
+void Client::parseResponse(int64_t id, const json_t *result, const json_t *error)
+{
+    if (json_is_object(error)) {
+        LOG_ERR("[%s:%u] error: \"%s\", code: %lld", m_host, m_port, json_string_value(json_object_get(error, "message")), json_integer_value(json_object_get(error, "code")));
+
+        if (id == 1) {
+            close();
+        }
+
+        return;
+    }
+
+    if (!json_is_object(result)) {
+        return;
+    }
+
+    if (id == 1) {
+        int code = -1;
+        if (!parseLogin(result, &code)) {
+            LOG_ERR("[%s:%u] login error code: %d", m_host, m_port, code);
+            return close();
+        }
+
+        m_failures = 0;
+        m_listener->onLoginSuccess(this);
+        m_listener->onJobReceived(this, m_job);
+        return;
+    }
+}
+
+
+void Client::ping()
+{
+    char *req = static_cast<char*>(malloc(128));
+    snprintf(req, 128, "{\"id\":%lld,\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId);
+
+    send(req);
+}
+
+
+void Client::reconnect()
+{
+    uv_timer_stop(&m_responseTimer);
+    if (m_keepAlive) {
+        uv_timer_stop(&m_keepAliveTimer);
+    }
+
+    if (m_failures == -1) {
+        return m_listener->onClose(this, -1);
+    }
+
+    m_failures++;
+    m_listener->onClose(this, m_failures);
+
+    uv_timer_start(&m_retriesTimer, [](uv_timer_t *handle) { getClient(handle->data)->connect(); }, m_retryPause, 0);
+}
+
+
+void Client::setState(SocketState state)
+{
+    LOG_DEBUG("[%s:%u] state: %d", m_host, m_port, state);
+
+    if (m_state == state) {
+        return;
+    }
+
+    m_state = state;
+}
+
+
+void Client::startTimeout()
+{
+    uv_timer_stop(&m_responseTimer);
+    if (!m_keepAlive) {
+        return;
+    }
+
+    uv_timer_start(&m_keepAliveTimer, [](uv_timer_t *handle) { getClient(handle->data)->ping(); }, kKeepAliveTimeout, 0);
+}
+
+
+void Client::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
+{
+    auto client = getClient(handle->data);
+
+    buf->base = &client->m_recvBuf.base[client->m_recvBufPos];
+    buf->len  = client->m_recvBuf.len - client->m_recvBufPos;
+}
+
+
+void Client::onClose(uv_handle_t *handle)
+{
+    auto client = getClient(handle->data);
+
+    free(client->m_socket);
+
+    client->m_stream = nullptr;
+    client->m_socket = nullptr;
+    client->setState(UnconnectedState);
+
+    client->reconnect();
+}
+
+
+void Client::onConnect(uv_connect_t *req, int status)
+{
+    auto client = getClient(req->data);
+    if (status < 0) {
+        LOG_ERR("[%s:%u] connect error: \"%s\"", client->m_host, client->m_port, uv_strerror(status));
+        free(req);
+        client->close();
+        return;
+    }
+
+    client->m_stream = static_cast<uv_stream_t*>(req->handle);
+    client->m_stream->data = req->data;
+    client->setState(ConnectedState);
+
+    uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead);
+    free(req);
+
+    client->m_listener->onLoginCredentialsRequired(client);
+}
+
+
+void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
+{
+    auto client = getClient(stream->data);
+    if (nread < 0) {
+        if (nread != UV_EOF) {
+            LOG_ERR("[%s:%u] read error: \"%s\"", client->m_host, client->m_port, uv_strerror(nread));
+        }
+
+        return client->close();;
+    }
+
+    client->m_recvBufPos += nread;
+
+    char* end;
+    char* start = client->m_recvBuf.base;
+    size_t remaining = client->m_recvBufPos;
+
+    while ((end = static_cast<char*>(memchr(start, '\n', remaining))) != nullptr) {
+        end++;
+        size_t len = end - start;
+        client->parse(start, len);
+
+        remaining -= len;
+        start = end;
+    }
+
+    if (remaining == 0) {
+        client->m_recvBufPos = 0;
+        return;
+    }
+
+    if (start == client->m_recvBuf.base) {
+        return;
+    }
+
+    memcpy(client->m_recvBuf.base, start, remaining);
+    client->m_recvBufPos = remaining;
+}
+
+
+void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res)
+{
+    auto client = getClient(req->data);
+    if (status < 0) {
+        LOG_ERR("[%s:%u] DNS error: \"%s\"", client->m_host, client->m_port, uv_strerror(status));
+        return client->reconnect();;
+    }
+
+    client->connect(res->ai_addr);
+    uv_freeaddrinfo(res);
+}
+
+
+Client *Client::getClient(void *data)
+{
+    return static_cast<Client*>(data);
+}
diff --git a/src/net/Client.h b/src/net/Client.h
new file mode 100644
index 000000000..75c5b2830
--- /dev/null
+++ b/src/net/Client.h
@@ -0,0 +1,121 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CLIENT_H__
+#define __CLIENT_H__
+
+
+#include <jansson.h>
+#include <uv.h>
+
+
+#include "net/Job.h"
+
+
+class IClientListener;
+class JobResult;
+class Url;
+
+
+class Client
+{
+public:
+    enum SocketState {
+        UnconnectedState,
+        HostLookupState,
+        ConnectingState,
+        ConnectedState,
+        ClosingState
+    };
+
+    constexpr static int kResponseTimeout  = 15 * 1000;
+    constexpr static int kKeepAliveTimeout = 60 * 1000;
+
+    Client(int id, IClientListener *listener);
+    ~Client();
+
+    void connect();
+    void connect(const Url *url);
+    void disconnect();
+    void login(const char *user, const char *pass, const char *agent);
+    void send(char *data);
+    void setUrl(const Url *url);
+    void submit(const JobResult &result);
+
+    inline bool isReady() const              { return m_state == ConnectedState && m_failures == 0; }
+    inline const char *host() const          { return m_host; }
+    inline const Job &job() const            { return m_job; }
+    inline int id() const                    { return m_id; }
+    inline SocketState state() const         { return m_state; }
+    inline uint16_t port() const             { return m_port; }
+    inline void setKeepAlive(bool keepAlive) { m_keepAlive = keepAlive; }
+    inline void setRetryPause(int ms)        { m_retryPause = ms; }
+
+private:
+    constexpr static size_t kRecvBufSize = 4096;
+
+    bool parseJob(const json_t *params, int *code);
+    bool parseLogin(const json_t *result, int *code);
+    int resolve(const char *host);
+    void close();
+    void connect(struct sockaddr *addr);
+    void parse(char *line, size_t len);
+    void parseNotification(const char *method, const json_t *params, const json_t *error);
+    void parseResponse(int64_t id, const json_t *result, const json_t *error);
+    void ping();
+    void reconnect();
+    void setState(SocketState state);
+    void startTimeout();
+
+    static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);
+    static void onClose(uv_handle_t *handle);
+    static void onConnect(uv_connect_t *req, int status);
+    static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
+    static void onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res);
+
+    static Client *getClient(void *data);
+
+    bool m_keepAlive;
+    char *m_host;
+    char m_rpcId[64];
+    IClientListener *m_listener;
+    int m_id;
+    int m_retryPause;
+    int64_t m_failures;
+    int64_t m_sequence;
+    Job m_job;
+    size_t m_recvBufPos;
+    SocketState m_state;
+    struct addrinfo m_hints;
+    uint16_t m_port;
+    uv_buf_t m_recvBuf;
+    uv_getaddrinfo_t m_resolver;
+    uv_stream_t *m_stream;
+    uv_tcp_t *m_socket;
+    uv_timer_t m_keepAliveTimer;
+    uv_timer_t m_responseTimer;
+    uv_timer_t m_retriesTimer;
+};
+
+
+#endif /* __CLIENT_H__ */
diff --git a/src/net/Job.cpp b/src/net/Job.cpp
new file mode 100644
index 000000000..52123485f
--- /dev/null
+++ b/src/net/Job.cpp
@@ -0,0 +1,158 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <string.h>
+//#include <stdlib.h>
+
+
+#include "net/Job.h"
+#include "Console.h"
+
+
+static inline unsigned char hf_hex2bin(char c, bool &err)
+{
+    if (c >= '0' && c <= '9') {
+        return c - '0';
+    }
+    else if (c >= 'a' && c <= 'f') {
+        return c - 'a' + 0xA;
+    }
+    else if (c >= 'A' && c <= 'F') {
+        return c - 'A' + 0xA;
+    }
+
+    err = true;
+    return 0;
+}
+
+
+static inline char hf_bin2hex(unsigned char c)
+{
+    if (c <= 0x9) {
+        return '0' + c;
+    }
+
+    return 'a' - 0xA + c;
+}
+
+
+Job::Job(int poolId) :
+    m_poolId(poolId),
+    m_size(0),
+    m_diff(0),
+    m_target(0)
+{
+}
+
+
+bool Job::setBlob(const char *blob)
+{
+    if (!blob) {
+        return false;
+    }
+
+    m_size = strlen(blob);
+    if (m_size % 2 != 0) {
+        return false;
+    }
+
+    m_size /= 2;
+    if (m_size < 76 || m_size >= sizeof(m_blob)) {
+        return false;
+    }
+
+    return fromHex(blob, m_size * 2, m_blob);
+}
+
+
+bool Job::setId(const char *id)
+{
+    if (!id || strlen(id) >= sizeof(m_id)) {
+        return false;
+    }
+
+    memset(m_id, 0, sizeof(m_id));
+    memcpy(m_id, id, strlen(id));
+    return true;
+}
+
+
+bool Job::setTarget(const char *target)
+{
+    if (!target) {
+        return false;
+    }
+
+    const size_t len = strlen(target);
+
+    if (len <= 8) {
+        uint32_t tmp = 0;
+        char str[8];
+        memcpy(str, target, len);
+
+        if (!fromHex(str, 8, reinterpret_cast<unsigned char*>(&tmp)) || tmp == 0) {
+            return false;
+        }
+
+        m_target = 0xFFFFFFFFFFFFFFFFULL / (0xFFFFFFFFULL / static_cast<uint64_t>(tmp));
+    }
+    else if (len <= 16) {
+        m_target = 0;
+        char str[16];
+        memcpy(str, target, len);
+
+        if (!fromHex(str, 16, reinterpret_cast<unsigned char*>(&m_target)) || m_target == 0) {
+            return false;
+        }
+    }
+    else {
+        return false;
+    }
+
+    m_diff = toDiff(m_target);
+    return true;
+}
+
+
+bool Job::fromHex(const char* in, unsigned int len, unsigned char* out)
+{
+    bool error = false;
+    for (unsigned int i = 0; i < len; i += 2) {
+        out[i / 2] = (hf_hex2bin(in[i], error) << 4) | hf_hex2bin(in[i + 1], error);
+
+        if (error) {
+            return false;
+        }
+    }
+    return true;
+}
+
+
+void Job::toHex(const unsigned char* in, unsigned int len, char* out)
+{
+    for (unsigned int i = 0; i < len; i++) {
+        out[i * 2] = hf_bin2hex((in[i] & 0xF0) >> 4);
+        out[i * 2 + 1] = hf_bin2hex(in[i] & 0x0F);
+    }
+}
diff --git a/src/net/Job.h b/src/net/Job.h
new file mode 100644
index 000000000..262465fca
--- /dev/null
+++ b/src/net/Job.h
@@ -0,0 +1,66 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __JOB_H__
+#define __JOB_H__
+
+
+#include <stdint.h>
+
+
+#include "align.h"
+
+
+class Job
+{
+public:
+    Job(int poolId = -2);
+    bool setBlob(const char *blob);
+    bool setId(const char *id);
+    bool setTarget(const char *target);
+
+    inline bool isValid() const        { return m_size > 0 && m_diff > 0; }
+    inline const char *id() const      { return m_id; }
+    inline const uint8_t *blob() const { return m_blob; }
+    inline int poolId() const          { return m_poolId; }
+    inline uint32_t *nonce()           { return reinterpret_cast<uint32_t*>(m_blob + 39); }
+    inline uint32_t diff() const       { return m_diff; }
+    inline uint32_t size() const       { return m_size; }
+    inline uint64_t target() const     { return m_target; }
+    inline void setPoolId(int poolId)  { m_poolId = poolId; }
+
+    static bool fromHex(const char* in, unsigned int len, unsigned char* out);
+    static inline uint32_t *nonce(uint8_t *blob)   { return reinterpret_cast<uint32_t*>(blob + 39); }
+    static inline uint64_t toDiff(uint64_t target) { return 0xFFFFFFFFFFFFFFFFULL / target; }
+    static void toHex(const unsigned char* in, unsigned int len, char* out);
+
+private:
+    int m_poolId;
+    VAR_ALIGN(16, char m_id[64]);
+    VAR_ALIGN(16, uint8_t m_blob[84]); // Max blob size is 84 (75 fixed + 9 variable), aligned to 96. https://github.com/xmrig/xmrig/issues/1 Thanks fireice-uk.
+    uint32_t m_size;
+    uint64_t m_diff;
+    uint64_t m_target;
+};
+
+#endif /* __JOB_H__ */
diff --git a/persistent_memory.h b/src/net/JobResult.h
similarity index 66%
rename from persistent_memory.h
rename to src/net/JobResult.h
index 5a6d6ca74..87e3a645a 100644
--- a/persistent_memory.h
+++ b/src/net/JobResult.h
@@ -21,30 +21,28 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __PERSISTENT_MEMORY_H__
-#define __PERSISTENT_MEMORY_H__
-
-#include <stddef.h>
+#ifndef __JOBRESULT_H__
+#define __JOBRESULT_H__
 
 
-enum memory_flags {
-    MEMORY_HUGEPAGES_AVAILABLE = 1,
-    MEMORY_HUGEPAGES_ENABLED   = 2,
-    MEMORY_LOCK                = 4
+#include <memory.h>
+#include <stdint.h>
+
+
+class JobResult
+{
+public:
+    inline JobResult() : poolId(0), nonce(0) {}
+    inline JobResult(int poolId, const char *jobId, uint32_t nonce, const uint8_t *result) : poolId(poolId), nonce(nonce)
+    {
+        memcpy(this->jobId, jobId, sizeof(this->jobId));
+        memcpy(this->result, result, sizeof(this->result));
+    }
+
+    char jobId[64];
+    int poolId;
+    uint32_t nonce;
+    uint8_t result[32];
 };
 
-
-#define MEMORY 2097152
-
-
-extern char *persistent_memory;
-extern int persistent_memory_flags;
-
-
-const char * persistent_memory_allocate();
-void persistent_memory_free();
-void * persistent_calloc(size_t num, size_t size);
-void * create_persistent_ctx(int thr_id);
-
-
-#endif /* __PERSISTENT_MEMORY_H__ */
+#endif /* __JOBRESULT_H__ */
diff --git a/src/net/Network.cpp b/src/net/Network.cpp
new file mode 100644
index 000000000..448f1ebb3
--- /dev/null
+++ b/src/net/Network.cpp
@@ -0,0 +1,217 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <memory>
+
+
+#include "Console.h"
+#include "net/Client.h"
+#include "net/Network.h"
+#include "net/Url.h"
+#include "Options.h"
+#include "workers/Workers.h"
+
+
+Network::Network(const Options *options) :
+    m_donate(false),
+    m_options(options),
+    m_pool(0),
+    m_diff(0)
+{
+    Workers::setListener(this);
+
+    m_pools.reserve(2);
+    m_agent = userAgent();
+
+    addPool(std::make_unique<Url>().get());
+    addPool(m_options->url());
+    addPool(m_options->backupUrl());
+
+    m_timer.data = this;
+    uv_timer_init(uv_default_loop(), &m_timer);
+}
+
+
+Network::~Network()
+{
+    for (auto client : m_pools) {
+        delete client;
+    }
+
+    free(m_agent);
+}
+
+
+void Network::connect()
+{
+    m_pools[1]->connect();
+
+    if (m_options->donateLevel()) {
+        uv_timer_start(&m_timer, Network::onTimer, (100 - m_options->donateLevel()) * 60 * 1000, 0);
+    }
+}
+
+
+void Network::onClose(Client *client, int failures)
+{
+    const int id = client->id();
+    if (id == 0) {
+        if (failures == -1) {
+            stopDonate();
+        }
+
+        return;
+    }
+
+    if (m_pool == id) {
+        m_pool = 0;
+        Workers::pause();
+    }
+
+    if (id == 1 && m_pools.size() > 2 && failures == m_options->retries()) {
+        m_pools[2]->connect();
+    }
+}
+
+
+void Network::onJobReceived(Client *client, const Job &job)
+{
+    if (m_donate && client->id() != 0) {
+        return;
+    }
+
+    setJob(client, job);
+}
+
+
+void Network::onJobResult(const JobResult &result)
+{
+    LOG_NOTICE("SHARE FOUND");
+    m_pools[result.poolId]->submit(result);
+}
+
+
+void Network::onLoginCredentialsRequired(Client *client)
+{
+    client->login(m_options->user(), m_options->pass(), m_agent);
+}
+
+
+void Network::onLoginSuccess(Client *client)
+{
+    const int id = client->id();
+    if (id == 0) {
+        return startDonate();
+    }
+
+    if (id == 2 && m_pool) { // primary pool is already active
+        m_pools[2]->disconnect();
+        return;
+    }
+
+    LOG_NOTICE("use pool: \"%s:%d\"", client->host(), client->port());
+    m_pool = id;
+
+    if (m_pool == 1 && m_pools.size() > 2) { // try disconnect from backup pool
+        m_pools[2]->disconnect();
+    }
+}
+
+
+void Network::addPool(const Url *url)
+{
+    if (!url) {
+        return;
+    }
+
+    Client *client = new Client(m_pools.size(), this);
+    client->setUrl(url);
+    client->setRetryPause(m_options->retryPause() * 1000);
+    client->setKeepAlive(m_options->keepAlive());
+
+    m_pools.push_back(client);
+}
+
+
+void Network::setJob(Client *client, const Job &job)
+{
+    if (m_options->colors()){
+        LOG_INFO("\x1B[01;33mnew job\x1B[0m from \"%s:%d\", diff: %d", client->host(), client->port(), job.diff());
+
+    }
+    else {
+        LOG_INFO("new job from \"%s:%d\", diff: %d", client->host(), client->port(), job.diff());
+    }
+
+    Workers::setJob(job);
+}
+
+
+void Network::startDonate()
+{
+    if (m_donate) {
+        return;
+    }
+
+    LOG_NOTICE("dev donate started");
+
+    m_donate = true;
+}
+
+
+void Network::stopDonate()
+{
+    if (!m_donate) {
+        return;
+    }
+
+    LOG_NOTICE("dev donate finished");
+
+    m_donate = false;
+    if (!m_pool) {
+        return;
+    }
+
+    Client *client = m_pools[m_pool];
+    if (client->isReady()) {
+        setJob(client, client->job());
+    }
+}
+
+
+void Network::onTimer(uv_timer_t *handle)
+{
+    auto net = static_cast<Network*>(handle->data);
+
+    if (!net->m_donate) {
+        auto url = std::make_unique<Url>("donate.xmrig.com", net->m_options->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 3333 : 443);
+        net->m_pools[0]->connect(url.get());
+
+        uv_timer_start(&net->m_timer, Network::onTimer, net->m_options->donateLevel() * 60 * 1000, 0);
+        return;
+    }
+
+    net->m_pools[0]->disconnect();
+    uv_timer_start(&net->m_timer, Network::onTimer, (100 - net->m_options->donateLevel()) * 60 * 1000, 0);
+}
diff --git a/src/net/Network.h b/src/net/Network.h
new file mode 100644
index 000000000..2859abc8f
--- /dev/null
+++ b/src/net/Network.h
@@ -0,0 +1,75 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NETWORK_H__
+#define __NETWORK_H__
+
+
+#include <vector>
+#include <uv.h>
+
+
+#include "interfaces/IClientListener.h"
+#include "interfaces/IJobResultListener.h"
+
+
+class Options;
+class Url;
+
+
+class Network : public IClientListener, public IJobResultListener
+{
+public:
+  Network(const Options *options);
+  ~Network();
+
+  void connect();
+
+  static char *userAgent();
+
+protected:
+  void onClose(Client *client, int failures) override;
+  void onJobReceived(Client *client, const Job &job) override;
+  void onJobResult(const JobResult &result) override;
+  void onLoginCredentialsRequired(Client *client) override;
+  void onLoginSuccess(Client *client) override;
+
+private:
+  void addPool(const Url *url);
+  void setJob(Client *client, const Job &job);
+  void startDonate();
+  void stopDonate();
+
+  static void onTimer(uv_timer_t *handle);
+
+  bool m_donate;
+  char *m_agent;
+  const Options *m_options;
+  int m_pool;
+  std::vector<Client*> m_pools;
+  uint64_t m_diff;
+  uv_timer_t m_timer;
+};
+
+
+#endif /* __NETWORK_H__ */
diff --git a/src/net/Network_mac.cpp b/src/net/Network_mac.cpp
new file mode 100644
index 000000000..c3c42a3e5
--- /dev/null
+++ b/src/net/Network_mac.cpp
@@ -0,0 +1,39 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <stdlib.h>
+
+#include "net/Network.h"
+#include "version.h"
+
+
+char *Network::userAgent()
+{
+    const size_t max = 128;
+
+    char *buf = static_cast<char*>(malloc(max));
+    snprintf(buf, max, "%s/%s (Macintosh; Intel Mac OS X) libuv/%s clang/%d.%d.%d", APP_NAME, APP_VERSION, uv_version_string(), __clang_major__, __clang_minor__, __clang_patchlevel__);
+
+    return buf;
+}
diff --git a/xmrig.h b/src/net/Network_unix.cpp
similarity index 62%
rename from xmrig.h
rename to src/net/Network_unix.cpp
index 08091367e..546d1b8a2 100644
--- a/xmrig.h
+++ b/src/net/Network_unix.cpp
@@ -21,37 +21,30 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __XMRIG_H__
-#define __XMRIG_H__
 
-#include <stdbool.h>
-#include <inttypes.h>
-#include <jansson.h>
-#include <curl/curl.h>
-#include <pthread.h>
-
-#define unlikely(expr) (__builtin_expect(!!(expr), 0))
-#define likely(expr)   (__builtin_expect(!!(expr), 1))
+#include <stdlib.h>
 
 
-struct thr_info {
-    int id;
-    pthread_t pth;
-    struct thread_q *q;
-};
+#include "net/Network.h"
+#include "version.h"
 
 
-struct work_restart {
-    volatile unsigned long restart;
-    char padding[128 - sizeof(unsigned long)];
-};
+char *Network::userAgent()
+{
+    const size_t max = 128;
 
+    char *buf = static_cast<char*>(malloc(max));
+    int length = snprintf(buf, max, "%s/%s (Linux ", APP_NAME, APP_VERSION);
 
-struct work;
+#   if defined(__x86_64__)
+    length += snprintf(buf + length, max - length, "x86_64) libuv/%s", uv_version_string());
+#   else
+    length += snprintf(buf + length, max - length, "i686) libuv/%s", uv_version_string());
+#   endif
 
+#   ifdef __GNUC__
+    length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
+#   endif
 
-extern struct thr_info *thr_info;
-extern struct work_restart *work_restart;
-extern void os_specific_init();
-
-#endif /* __XMRIG_H__ */
+    return buf;
+}
diff --git a/src/net/Network_win.cpp b/src/net/Network_win.cpp
new file mode 100644
index 000000000..6ae5e3223
--- /dev/null
+++ b/src/net/Network_win.cpp
@@ -0,0 +1,72 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <winsock2.h>
+#include <windows.h>
+
+
+#include "net/Network.h"
+#include "version.h"
+
+
+static inline OSVERSIONINFOEX winOsVersion()
+{
+    typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO);
+    OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0};
+
+    HMODULE ntdll = GetModuleHandleW(L"ntdll.dll");
+    if (ntdll ) {
+        RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(GetProcAddress(ntdll, "RtlGetVersion"));
+
+        if (pRtlGetVersion) {
+            pRtlGetVersion((LPOSVERSIONINFO) &result);
+        }
+    }
+
+    return result;
+}
+
+
+char *Network::userAgent()
+{
+    const auto osver = winOsVersion();
+    const size_t max = 128;
+
+    char *buf = static_cast<char*>(malloc(max));
+    int length = snprintf(buf, max, "%s/%s (Windows NT %lu.%lu", APP_NAME, APP_VERSION, osver.dwMajorVersion, osver.dwMinorVersion);
+
+#   if defined(__x86_64__) || defined(_M_AMD64)
+    length += snprintf(buf + length, max - length, "; Win64; x64) libuv/%s", uv_version_string());
+#   else
+    length += snprintf(buf + length, max - length, ") libuv/%s", uv_version_string());
+#   endif
+
+#   ifdef __GNUC__
+    length += snprintf(buf + length, max - length, " gcc/%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
+#   elif _MSC_VER
+    length += snprintf(buf + length, max - length, " msvc/%d", MSVC_VERSION);
+#   endif
+
+    return buf;
+}
diff --git a/src/net/Url.cpp b/src/net/Url.cpp
new file mode 100644
index 000000000..d8264c20e
--- /dev/null
+++ b/src/net/Url.cpp
@@ -0,0 +1,105 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+
+
+#include "net/Url.h"
+
+
+#ifdef _MSC_VER
+#   define strncasecmp(x,y,z) _strnicmp(x,y,z)
+#endif
+
+
+Url::Url() :
+    m_host(nullptr),
+    m_port(3333)
+{
+}
+
+
+/**
+ * @brief Parse url.
+ *
+ * Valid urls:
+ * example.com
+ * example.com:3333
+ * stratum+tcp://example.com
+ * stratum+tcp://example.com:3333
+ *
+ * @param url
+ */
+Url::Url(const char *url) :
+    m_host(nullptr),
+    m_port(3333)
+{
+    const char *p = strstr(url, "://");
+    const char *base = url;
+
+    if (p) {
+        if (strncasecmp(url, "stratum+tcp://", 14)) {
+            return;
+        }
+
+        base = url + 14;
+    }
+
+    if (!strlen(base) || *base == '/') {
+        return;
+    }
+
+    const char *port = strchr(base, ':');
+    if (!port) {
+        m_host = strdup(base);
+        return;
+    }
+
+    const size_t size = port++ - base + 1;
+    m_host = static_cast<char*>(malloc(size));
+    memcpy(m_host, base, size - 1);
+    m_host[size - 1] = '\0';
+
+    m_port = strtol(port, nullptr, 10);
+}
+
+
+Url::Url(const char *host, uint16_t port) :
+    m_port(port)
+{
+    m_host = strdup(host);
+}
+
+
+Url::~Url()
+{
+    free(m_host);
+}
+
+
+bool Url::isNicehash() const
+{
+    return isValid() && strstr(m_host, ".nicehash.com");
+}
diff --git a/src/net/Url.h b/src/net/Url.h
new file mode 100644
index 000000000..7d44501d2
--- /dev/null
+++ b/src/net/Url.h
@@ -0,0 +1,50 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __URL_H__
+#define __URL_H__
+
+
+#include <stdint.h>
+
+
+class Url
+{
+public:
+    Url();
+    Url(const char *url);
+    Url(const char *host, uint16_t port);
+    ~Url();
+
+    bool isNicehash() const;
+
+    inline bool isValid() const     { return m_host && m_port > 0; }
+    inline const char *host() const { return m_host; }
+    inline uint16_t port() const    { return m_port; }
+
+private:
+    char *m_host;
+    uint16_t m_port;
+};
+
+#endif /* __URL_H__ */
diff --git a/version.h b/src/version.h
similarity index 74%
rename from version.h
rename to src/version.h
index 8804e2713..326b65672 100644
--- a/version.h
+++ b/src/version.h
@@ -27,14 +27,30 @@
 #define APP_ID        "xmrig"
 #define APP_NAME      "XMRig"
 #define APP_DESC      "Monero (XMR) CPU miner"
-#define APP_VERSION   "0.8.1"
+#define APP_VERSION   "1.0.0-dev"
 #define APP_DOMAIN    "xmrig.com"
 #define APP_SITE      "www.xmrig.com"
 #define APP_COPYRIGHT "Copyright (C) 2016-2017 xmrig.com"
 
-#define APP_VER_MAJOR  0
-#define APP_VER_MINOR  8
-#define APP_VER_BUILD  1
+#define APP_VER_MAJOR  1
+#define APP_VER_MINOR  0
+#define APP_VER_BUILD  0
 #define APP_VER_REV    0
 
+#ifdef _MSC_VER
+#   if _MSC_VER == 1910
+#       define MSVC_VERSION 2017
+#   elif _MSC_VER == 1900
+#       define MSVC_VERSION 2015
+#   elif _MSC_VER == 1800
+#       define MSVC_VERSION 2013
+#   elif _MSC_VER == 1700
+#       define MSVC_VERSION 2012
+#   elif _MSC_VER == 1600
+#       define MSVC_VERSION 2010
+#   else
+#       define MSVC_VERSION 0
+#   endif
+#endif
+
 #endif /* __VERSION_H__ */
diff --git a/src/workers/DoubleWorker.cpp b/src/workers/DoubleWorker.cpp
new file mode 100644
index 000000000..41b9aec79
--- /dev/null
+++ b/src/workers/DoubleWorker.cpp
@@ -0,0 +1,96 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <thread>
+
+
+#include "crypto/CryptoNight.h"
+#include "workers/DoubleWorker.h"
+#include "workers/Workers.h"
+
+
+DoubleWorker::DoubleWorker(Handle *handle)
+    : Worker(handle),
+    m_nonce1(0),
+    m_nonce2(0)
+{
+}
+
+
+void DoubleWorker::start()
+{
+    while (true) {
+        if (Workers::isPaused()) {
+            do {
+                std::this_thread::sleep_for(std::chrono::milliseconds(200));
+            }
+            while (Workers::isPaused());
+
+            consumeJob();
+        }
+
+        while (!Workers::isOutdated(m_sequence)) {
+            if ((m_count & 0xF) == 0) {
+                storeStats();
+            }
+
+            m_count += 2;
+            *Job::nonce(m_blob)                = ++m_nonce1;
+            *Job::nonce(m_blob + m_job.size()) = ++m_nonce2;
+
+            CryptoNight::hash(m_blob, m_job.size(), m_hash, m_ctx);
+
+            if (*reinterpret_cast<uint64_t*>(m_hash + 24) < m_job.target()) {
+                Workers::submit(JobResult(m_job.poolId(), m_job.id(), m_nonce1, m_hash));
+            }
+
+            if (*reinterpret_cast<uint64_t*>(m_hash + 32 + 24) < m_job.target()) {
+                Workers::submit(JobResult(m_job.poolId(), m_job.id(), m_nonce2, m_hash + 32));
+            }
+
+            std::this_thread::yield();
+        }
+
+        consumeJob();
+    }
+}
+
+
+void DoubleWorker::consumeJob()
+{
+    m_job = Workers::job();
+    m_sequence = Workers::sequence();
+
+    memcpy(m_blob,                m_job.blob(), m_job.size());
+    memcpy(m_blob + m_job.size(), m_job.blob(), m_job.size());
+
+    if (m_nicehash) {
+        m_nonce1 = (*Job::nonce(m_blob)                & 0xff000000U) + (0xffffffU / (m_threads * 2) * m_id);
+        m_nonce2 = (*Job::nonce(m_blob + m_job.size()) & 0xff000000U) + (0xffffffU / (m_threads * 2) * (m_id + m_threads));
+    }
+    else {
+        m_nonce1 = 0xffffffffU / (m_threads * 2) * m_id;
+        m_nonce2 = 0xffffffffU / (m_threads * 2) * (m_id + m_threads);
+    }
+}
diff --git a/src/workers/DoubleWorker.h b/src/workers/DoubleWorker.h
new file mode 100644
index 000000000..d062dac0c
--- /dev/null
+++ b/src/workers/DoubleWorker.h
@@ -0,0 +1,55 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DOUBLEWORKER_H__
+#define __DOUBLEWORKER_H__
+
+
+#include "align.h"
+#include "net/Job.h"
+#include "net/JobResult.h"
+#include "workers/Worker.h"
+
+
+class Handle;
+
+
+class DoubleWorker : public Worker
+{
+public:
+    DoubleWorker(Handle *handle);
+
+    void start() override;
+
+private:
+    void consumeJob();
+
+    Job m_job;
+    uint32_t m_nonce1;
+    uint32_t m_nonce2;
+    uint8_t m_hash[64];
+    uint8_t	m_blob[84 * 2];
+};
+
+
+#endif /* __SINGLEWORKER_H__ */
diff --git a/src/workers/Handle.cpp b/src/workers/Handle.cpp
new file mode 100644
index 000000000..c97d10b12
--- /dev/null
+++ b/src/workers/Handle.cpp
@@ -0,0 +1,41 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "workers/Handle.h"
+
+
+Handle::Handle(int threadId, int threads, int64_t affinity, bool nicehash) :
+    m_nicehash(nicehash),
+    m_threadId(threadId),
+    m_threads(threads),
+    m_affinity(affinity),
+    m_worker(nullptr)
+{
+}
+
+
+void Handle::start(void (*callback) (void *))
+{
+    uv_thread_create(&m_thread, callback, this);
+}
diff --git a/src/workers/Handle.h b/src/workers/Handle.h
new file mode 100644
index 000000000..96a512e37
--- /dev/null
+++ b/src/workers/Handle.h
@@ -0,0 +1,58 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HANDLE_H__
+#define __HANDLE_H__
+
+
+#include <stdint.h>
+#include <uv.h>
+
+
+class IWorker;
+
+
+class Handle
+{
+public:
+    Handle(int threadId, int threads, int64_t affinity, bool nicehash);
+    void start(void (*callback) (void *));
+
+    inline bool nicehash() const           { return m_nicehash; }
+    inline int threadId() const            { return m_threadId; }
+    inline int threads() const             { return m_threads; }
+    inline int64_t affinity() const        { return m_affinity; }
+    inline IWorker *worker() const         { return m_worker; }
+    inline void setWorker(IWorker *worker) { m_worker = worker; }
+
+private:
+    bool m_nicehash;
+    int m_threadId;
+    int m_threads;
+    int64_t m_affinity;
+    IWorker *m_worker;
+    uv_thread_t m_thread;
+};
+
+
+#endif /* __HANDLE_H__ */
diff --git a/src/workers/SingleWorker.cpp b/src/workers/SingleWorker.cpp
new file mode 100644
index 000000000..9c56b7d8f
--- /dev/null
+++ b/src/workers/SingleWorker.cpp
@@ -0,0 +1,86 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <thread>
+
+
+#include "crypto/CryptoNight.h"
+#include "workers/SingleWorker.h"
+#include "workers/Workers.h"
+
+
+SingleWorker::SingleWorker(Handle *handle)
+    : Worker(handle)
+{
+}
+
+
+void SingleWorker::start()
+{
+    while (true) {
+        if (Workers::isPaused()) {
+            do {
+                std::this_thread::sleep_for(std::chrono::milliseconds(200));
+            }
+            while (Workers::isPaused());
+
+            consumeJob();
+        }
+
+        while (!Workers::isOutdated(m_sequence)) {
+            if ((m_count & 0xF) == 0) {
+                storeStats();
+            }
+
+            m_count++;
+            *m_job.nonce() = ++m_result.nonce;
+
+            if (CryptoNight::hash(m_job, m_result, m_ctx)) {
+                Workers::submit(m_result);
+            }
+
+            std::this_thread::yield();
+        }
+
+        consumeJob();
+    }
+}
+
+
+
+void SingleWorker::consumeJob()
+{
+    m_job = Workers::job();
+    m_sequence = Workers::sequence();
+
+    memcpy(m_result.jobId, m_job.id(), sizeof(m_result.jobId));
+    m_result.poolId = m_job.poolId();
+
+    if (m_nicehash) {
+        m_result.nonce = (*m_job.nonce() & 0xff000000U) + (0xffffffU / m_threads * m_id);
+    }
+    else {
+        m_result.nonce = 0xffffffffU / m_threads * m_id;
+    }
+}
diff --git a/src/workers/SingleWorker.h b/src/workers/SingleWorker.h
new file mode 100644
index 000000000..6ba59468a
--- /dev/null
+++ b/src/workers/SingleWorker.h
@@ -0,0 +1,51 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SINGLEWORKER_H__
+#define __SINGLEWORKER_H__
+
+
+#include "net/Job.h"
+#include "net/JobResult.h"
+#include "workers/Worker.h"
+
+
+class Handle;
+
+
+class SingleWorker : public Worker
+{
+public:
+    SingleWorker(Handle *handle);
+
+    void start() override;
+
+private:
+    void consumeJob();
+
+    Job m_job;
+    JobResult m_result;
+};
+
+
+#endif /* __SINGLEWORKER_H__ */
diff --git a/src/workers/Telemetry.cpp b/src/workers/Telemetry.cpp
new file mode 100644
index 000000000..b1a36633e
--- /dev/null
+++ b/src/workers/Telemetry.cpp
@@ -0,0 +1,107 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <memory.h>
+#include <math.h>
+#include <chrono>
+
+#include "Console.h"
+#include "workers/Telemetry.h"
+
+
+Telemetry::Telemetry(int threads) :
+    m_threads(threads)
+{
+    m_counts     = new uint64_t*[threads];
+    m_timestamps = new uint64_t*[threads];
+    m_top        = new uint32_t[threads];
+
+    for (int i = 0; i < threads; i++) {
+        m_counts[i] = new uint64_t[kBucketSize];
+        m_timestamps[i] = new uint64_t[kBucketSize];
+        m_top[i] = 0;
+
+        memset(m_counts[0], 0, sizeof(uint64_t) * kBucketSize);
+        memset(m_timestamps[0], 0, sizeof(uint64_t) * kBucketSize);
+    }
+}
+
+
+double Telemetry::calc(size_t threadId, size_t ms) const
+{
+    using namespace std::chrono;
+    const uint64_t now = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
+
+    uint64_t earliestHashCount = 0;
+    uint64_t earliestStamp     = 0;
+    uint64_t lastestStamp      = 0;
+    uint64_t lastestHashCnt    = 0;
+    bool haveFullSet           = false;
+
+    for (size_t i = 1; i < kBucketSize; i++) {
+        const size_t idx = (m_top[threadId] - i) & kBucketMask;
+
+        if (m_timestamps[threadId][idx] == 0) {
+            break;
+        }
+
+        if (lastestStamp == 0) {
+            lastestStamp = m_timestamps[threadId][idx];
+            lastestHashCnt = m_counts[threadId][idx];
+        }
+
+        if (now - m_timestamps[threadId][idx] > ms) {
+            haveFullSet = true;
+            break;
+        }
+
+        earliestStamp = m_timestamps[threadId][idx];
+        earliestHashCount = m_counts[threadId][idx];
+    }
+
+    if (!haveFullSet || earliestStamp == 0 || lastestStamp == 0) {
+        return nan("");
+    }
+
+    if (lastestStamp - earliestStamp == 0) {
+        return nan("");
+    }
+
+    double hashes, time;
+    hashes = lastestHashCnt - earliestHashCount;
+    time   = lastestStamp - earliestStamp;
+    time  /= 1000.0;
+
+    return hashes / time;
+}
+
+
+void Telemetry::add(size_t threadId, uint64_t count, uint64_t timestamp)
+{
+    const size_t top = m_top[threadId];
+    m_counts[threadId][top]     = count;
+    m_timestamps[threadId][top] = timestamp;
+
+    m_top[threadId] = (top + 1) & kBucketMask;
+}
diff --git a/util.h b/src/workers/Telemetry.h
similarity index 68%
rename from util.h
rename to src/workers/Telemetry.h
index 47ab8904b..007ba536e 100644
--- a/util.h
+++ b/src/workers/Telemetry.h
@@ -21,23 +21,29 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __UTIL_H__
-#define __UTIL_H__
-
-#include <jansson.h>
+#ifndef __TELEMETRY_H__
+#define __TELEMETRY_H__
 
 
-json_t *json_decode(const char *s);
-
-char *bin2hex(const unsigned char *p, size_t len);
-bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
-
-struct thread_q *tq_new(void);
-void tq_free(struct thread_q *tq);
-bool tq_push(struct thread_q *tq, void *data);
-void *tq_pop(struct thread_q *tq, const struct timespec *abstime);
-void tq_freeze(struct thread_q *tq);
-void tq_thaw(struct thread_q *tq);
+#include <stdint.h>
 
 
-#endif /* __UTIL_H__ */
+class Telemetry
+{
+public:
+    Telemetry(int threads);
+    double calc(size_t threadId, size_t ms) const;
+    void add(size_t threadId, uint64_t count, uint64_t timestamp);
+
+private:
+    constexpr static size_t kBucketSize = 2 << 11;
+    constexpr static size_t kBucketMask = kBucketSize - 1;
+
+    int m_threads;
+    uint32_t* m_top;
+    uint64_t** m_counts;
+    uint64_t** m_timestamps;
+};
+
+
+#endif /* __TELEMETRY_H__ */
diff --git a/src/workers/Worker.cpp b/src/workers/Worker.cpp
new file mode 100644
index 000000000..1cede65fe
--- /dev/null
+++ b/src/workers/Worker.cpp
@@ -0,0 +1,63 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <chrono>
+
+#include "Console.h"
+
+#include "Cpu.h"
+#include "Mem.h"
+#include "workers/Handle.h"
+#include "workers/Worker.h"
+
+
+Worker::Worker(Handle *handle) :
+    m_nicehash(handle->nicehash()),
+    m_id(handle->threadId()),
+    m_threads(handle->threads()),
+    m_hashCount(0),
+    m_timestamp(0),
+    m_count(0),
+    m_sequence(0)
+{
+    if (Cpu::threads() > 1 && handle->affinity() != -1L) {
+        Cpu::setAffinity(m_id, handle->affinity());
+    }
+
+    m_ctx = Mem::create(m_id);
+}
+
+
+Worker::~Worker()
+{
+}
+
+
+void Worker::storeStats()
+{
+    using namespace std::chrono;
+
+    const uint64_t timestamp = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
+    m_hashCount.store(m_count, std::memory_order_relaxed);
+    m_timestamp.store(timestamp, std::memory_order_relaxed);
+}
diff --git a/src/workers/Worker.h b/src/workers/Worker.h
new file mode 100644
index 000000000..84f3ccf87
--- /dev/null
+++ b/src/workers/Worker.h
@@ -0,0 +1,62 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __WORKER_H__
+#define __WORKER_H__
+
+
+#include <atomic>
+#include <stdint.h>
+
+
+#include "interfaces/IWorker.h"
+
+
+struct cryptonight_ctx;
+class Handle;
+
+
+class Worker : public IWorker
+{
+public:
+    Worker(Handle *handle);
+    ~Worker();
+
+    inline uint64_t hashCount() const override { return m_hashCount.load(std::memory_order_relaxed); }
+    inline uint64_t timestamp() const override { return m_timestamp.load(std::memory_order_relaxed); }
+
+protected:
+    void storeStats();
+
+    bool m_nicehash;
+    cryptonight_ctx *m_ctx;
+    int m_id;
+    int m_threads;
+    std::atomic<uint64_t> m_hashCount;
+    std::atomic<uint64_t> m_timestamp;
+    uint64_t m_count;
+    uint64_t m_sequence;
+};
+
+
+#endif /* __WORKER_H__ */
diff --git a/src/workers/Workers.cpp b/src/workers/Workers.cpp
new file mode 100644
index 000000000..b512d282f
--- /dev/null
+++ b/src/workers/Workers.cpp
@@ -0,0 +1,167 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <cmath>
+
+
+#include "Console.h"
+#include "interfaces/IJobResultListener.h"
+#include "Mem.h"
+#include "workers/DoubleWorker.h"
+#include "workers/Handle.h"
+#include "workers/SingleWorker.h"
+#include "workers/Telemetry.h"
+#include "workers/Workers.h"
+
+
+IJobResultListener *Workers::m_listener = nullptr;
+Job Workers::m_job;
+std::atomic<int> Workers::m_paused;
+std::atomic<uint64_t> Workers::m_sequence;
+std::list<JobResult> Workers::m_queue;
+std::vector<Handle*> Workers::m_workers;
+Telemetry *Workers::m_telemetry = nullptr;
+uint64_t Workers::m_ticks = 0;
+uv_async_t Workers::m_async;
+uv_mutex_t Workers::m_mutex;
+uv_rwlock_t Workers::m_rwlock;
+uv_timer_t Workers::m_timer;
+
+
+Job Workers::job()
+{
+    uv_rwlock_rdlock(&m_rwlock);
+    Job job = m_job;
+    uv_rwlock_rdunlock(&m_rwlock);
+
+    return job;
+}
+
+
+void Workers::setJob(const Job &job)
+{
+    uv_rwlock_wrlock(&m_rwlock);
+    m_job = job;
+    uv_rwlock_wrunlock(&m_rwlock);
+
+    m_sequence++;
+    m_paused = 0;
+}
+
+
+void Workers::start(int64_t affinity, bool nicehash)
+{
+    const int threads = Mem::threads();
+    m_telemetry = new Telemetry(threads);
+
+    uv_mutex_init(&m_mutex);
+    uv_rwlock_init(&m_rwlock);
+
+    m_sequence = 0;
+    m_paused   = 1;
+
+    uv_async_init(uv_default_loop(), &m_async, Workers::onResult);
+    uv_timer_init(uv_default_loop(), &m_timer);
+    uv_timer_start(&m_timer, Workers::onTick, 500, 500);
+
+    for (int i = 0; i < threads; ++i) {
+        Handle *handle = new Handle(i, threads, affinity, nicehash);
+        m_workers.push_back(handle);
+        handle->start(Workers::onReady);
+    }
+}
+
+
+void Workers::submit(const JobResult &result)
+{
+    uv_mutex_lock(&m_mutex);
+    m_queue.push_back(result);
+    uv_mutex_unlock(&m_mutex);
+
+    uv_async_send(&m_async);
+}
+
+
+
+void Workers::onReady(void *arg)
+{
+    auto handle = static_cast<Handle*>(arg);
+    if (Mem::isDoubleHash()) {
+        handle->setWorker(new DoubleWorker(handle));
+    }
+    else {
+        handle->setWorker(new SingleWorker(handle));
+    }
+
+    handle->worker()->start();
+}
+
+
+void Workers::onResult(uv_async_t *handle)
+{
+    std::list<JobResult> results;
+
+    uv_mutex_lock(&m_mutex);
+    while (!m_queue.empty()) {
+        results.push_back(std::move(m_queue.front()));
+        m_queue.pop_front();
+    }
+    uv_mutex_unlock(&m_mutex);
+
+    for (auto result : results) {
+        m_listener->onJobResult(result);
+    }
+
+    results.clear();
+}
+
+
+void Workers::onTick(uv_timer_t *handle)
+{
+    for (Handle *handle : m_workers) {
+        if (handle->worker()) {
+            m_telemetry->add(handle->threadId(), handle->worker()->hashCount(), handle->worker()->timestamp());
+        }
+    }
+
+    if ((m_ticks++ & 0xF) == 0)  {
+        double hps = 0.0;
+        double telem;
+        bool normal = true;
+
+        for (Handle *handle : m_workers) {
+            telem = m_telemetry->calc(handle->threadId(), 2500);
+            if (!std::isnormal(telem)) {
+                normal = false;
+                break;
+            }
+            else {
+                hps += telem;
+            }
+        }
+
+        if (normal) {
+            LOG_NOTICE("%03.1f H/s", hps);
+        }
+    }
+}
diff --git a/src/workers/Workers.h b/src/workers/Workers.h
new file mode 100644
index 000000000..6cf17de4b
--- /dev/null
+++ b/src/workers/Workers.h
@@ -0,0 +1,76 @@
+/* XMRig
+ * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
+ * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
+ * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
+ * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
+ * Copyright 2016-2017 XMRig       <support@xmrig.com>
+ *
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __WORKERS_H__
+#define __WORKERS_H__
+
+
+#include <atomic>
+#include <list>
+#include <uv.h>
+#include <vector>
+
+#include "net/Job.h"
+#include "net/JobResult.h"
+
+
+class Handle;
+class IJobResultListener;
+class Telemetry;
+
+
+class Workers
+{
+public:
+    static Job job();
+    static void setJob(const Job &job);
+    static void start(int64_t affinity, bool nicehash);
+    static void submit(const JobResult &result);
+
+    static inline bool isOutdated(uint64_t sequence)             { return m_sequence.load(std::memory_order_relaxed) != sequence; }
+    static inline bool isPaused()                                { return m_paused.load(std::memory_order_relaxed) == 1; }
+    static inline uint64_t sequence()                            { return m_sequence.load(std::memory_order_relaxed); }
+    static inline void pause()                                   { m_paused = 1; }
+    static inline void setListener(IJobResultListener *listener) { m_listener = listener; }
+
+private:
+    static void onReady(void *arg);
+    static void onResult(uv_async_t *handle);
+    static void onTick(uv_timer_t *handle);
+
+    static IJobResultListener *m_listener;
+    static Job m_job;
+    static std::atomic<int> m_paused;
+    static std::atomic<uint64_t> m_sequence;
+    static std::list<JobResult> m_queue;
+    static std::vector<Handle*> m_workers;
+    static Telemetry *m_telemetry;
+    static uint64_t m_ticks;
+    static uv_async_t m_async;
+    static uv_mutex_t m_mutex;
+    static uv_rwlock_t m_rwlock;
+    static uv_timer_t m_timer;
+};
+
+
+#endif /* __WORKERS_H__ */
diff --git a/donate.h b/src/xmrig.cpp
similarity index 90%
rename from donate.h
rename to src/xmrig.cpp
index 4fc607872..4b4afcd28 100644
--- a/donate.h
+++ b/src/xmrig.cpp
@@ -21,9 +21,11 @@
  *   along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __DONATE_H__
-#define __DONATE_H__
+#include "App.h"
 
-#define DONATE_LEVEL 5
 
-#endif /* __DONATE_H__ */
+int main(int argc, char **argv) {
+    auto app = new App(argc, argv);
+
+    return app->exec();
+}
diff --git a/stats.c b/stats.c
deleted file mode 100644
index ee1316724..000000000
--- a/stats.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <pthread.h>
-#include <sys/time.h>
-#include <stdlib.h>
-
-#include "stats.h"
-#include "options.h"
-#include "utils/applog.h"
-#include "persistent_memory.h"
-
-
-static unsigned long accepted_count = 0L;
-static unsigned long rejected_count = 0L;
-static double *thr_hashrates;
-static double *thr_times;
-static uint32_t target = 0;
-
-pthread_mutex_t stats_lock;
-
-
-static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
-
-
-/**
- * @brief stats_init
- */
-void stats_init() {
-    pthread_mutex_init(&stats_lock, NULL);
-
-    thr_hashrates = (double *) persistent_calloc(opt_n_threads, sizeof(double));
-    thr_times = (double *) persistent_calloc(opt_n_threads, sizeof(double));
-}
-
-
-
-/**
- * @brief stats_set_target
- * @param target
- */
-void stats_set_target(uint32_t new_target)
-{
-    target = new_target;
-
-    applog(LOG_DEBUG, "Pool set diff to %g", ((double) 0xffffffff) / target);
-}
-
-
-/**
- * @brief stats_share_result
- * @param result
- */
-void stats_share_result(bool success)
-{
-    double hashrate = 0.0;
-
-    pthread_mutex_lock(&stats_lock);
-
-    for (int i = 0; i < opt_n_threads; i++) {
-        if (thr_times[i] > 0) {
-            hashrate += thr_hashrates[i] / thr_times[i];
-        }
-    }
-
-    success ? accepted_count++ : rejected_count++;
-    pthread_mutex_unlock(&stats_lock);
-
-    applog(LOG_INFO, "accepted: %lu/%lu (%.2f%%), %.2f H/s at diff %g",
-            accepted_count, accepted_count + rejected_count,
-            100. * accepted_count / (accepted_count + rejected_count), hashrate,
-            (((double) 0xffffffff) / target));
-}
-
-
-void stats_add_hashes(int thr_id, struct timeval *tv_start, unsigned long hashes_done)
-{
-    struct timeval tv_end, diff;
-
-    /* record scanhash elapsed time */
-    gettimeofday(&tv_end, NULL);
-    timeval_subtract(&diff, &tv_end, tv_start);
-
-    if (diff.tv_usec || diff.tv_sec) {
-        pthread_mutex_lock(&stats_lock);
-        thr_hashrates[thr_id] = hashes_done;
-        thr_times[thr_id] = (diff.tv_sec + 1e-6 * diff.tv_usec);
-        pthread_mutex_unlock(&stats_lock);
-    }
-}
-
-
-/* Subtract the `struct timeval' values X and Y,
-   storing the result in RESULT.
-   Return 1 if the difference is negative, otherwise 0.  */
-static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
-{
-    /* Perform the carry for the later subtraction by updating Y. */
-    if (x->tv_usec < y->tv_usec) {
-        int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
-        y->tv_usec -= 1000000 * nsec;
-        y->tv_sec += nsec;
-    }
-    if (x->tv_usec - y->tv_usec > 1000000) {
-        int nsec = (x->tv_usec - y->tv_usec) / 1000000;
-        y->tv_usec += 1000000 * nsec;
-        y->tv_sec -= nsec;
-    }
-
-    /* Compute the time remaining to wait.
-     * `tv_usec' is certainly positive. */
-    result->tv_sec = x->tv_sec - y->tv_sec;
-    result->tv_usec = x->tv_usec - y->tv_usec;
-
-    /* Return 1 if result is negative. */
-    return x->tv_sec < y->tv_sec;
-}
diff --git a/stratum.c b/stratum.c
deleted file mode 100644
index 1f2a4b8e6..000000000
--- a/stratum.c
+++ /dev/null
@@ -1,709 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <jansson.h>
-#include <unistd.h>
-
-#if defined(WIN32)
-#   include <winsock2.h>
-#   include <mstcpip.h>
-#else
-#   include <errno.h>
-#   include <netinet/tcp.h>
-#   include <poll.h>
-#endif
-
-#include "stratum.h"
-#include "version.h"
-#include "stats.h"
-#include "util.h"
-#include "utils/applog.h"
-
-
-#ifdef WIN32
-#   define socket_blocks() (WSAGetLastError() == WSAEWOULDBLOCK)
-#   define poll(fdarray, nfds, timeout) WSAPoll(fdarray, nfds, timeout)
-#   define SHUT_RDWR SD_BOTH
-#else
-#   define socket_blocks() (errno == EAGAIN || errno == EWOULDBLOCK)
-#   define closesocket(x) close((x))
-#endif
-
-#define RBUFSIZE 2048
-#define RECVSIZE (RBUFSIZE - 4)
-
-#define unlikely(expr) (__builtin_expect(!!(expr), 0))
-
-
-static struct work work;
-
-
-static bool send_line(curl_socket_t sock, char *s);
-static bool socket_full(curl_socket_t sock, int timeout);
-static void buffer_append(struct stratum_ctx *sctx, const char *s);
-static bool job(struct stratum_ctx *sctx, json_t *params);
-static int sockopt_keepalive_cb(void *userdata, curl_socket_t fd, curlsocktype purpose);
-static curl_socket_t opensocket_grab_cb(void *clientp, curlsocktype purpose, struct curl_sockaddr *addr);
-static int closesocket_cb(void *clientp, curl_socket_t item);
-static bool login_decode(struct stratum_ctx *sctx, const json_t *val);
-static bool job_decode(const json_t *job);
-static bool jobj_binary(const json_t *obj, const char *key, void *buf, size_t buflen);
-
-
-/**
- * @brief stratum_socket_full
- * @param sctx
- * @param timeout
- * @return
- */
-bool stratum_socket_full(struct stratum_ctx *sctx, int timeout)
-{
-    return strlen(sctx->sockbuf) || socket_full(sctx->sock, timeout);
-}
-
-
-/**
- * @brief stratum_send_line
- * @param sctx
- * @param s
- * @return
- */
-bool stratum_send_line(struct stratum_ctx *sctx, char *s)
-{
-    bool ret = false;
-
-    pthread_mutex_lock(&sctx->sock_lock);
-    ret = send_line(sctx->sock, s);
-    pthread_mutex_unlock(&sctx->sock_lock);
-
-    return ret;
-}
-
-
-/**
- * @brief stratum_recv_line
- * @param sctx
- * @return
- */
-char *stratum_recv_line(struct stratum_ctx *sctx)
-{
-    if (!strstr(sctx->sockbuf, "\n")) {
-        bool ret = true;
-        time_t rstart;
-
-        time(&rstart);
-
-        if (!socket_full(sctx->sock, 60)) {
-            applog(LOG_ERR, "stratum_recv_line timed out");
-            return NULL;
-        }
-
-        do {
-            char s[RBUFSIZE];
-            ssize_t n;
-
-            memset(s, 0, RBUFSIZE);
-            n = recv(sctx->sock, s, RECVSIZE, 0);
-            if (!n) {
-                ret = false;
-                break;
-            }
-
-            if (n < 0) {
-                if (!socket_blocks() || !socket_full(sctx->sock, 1)) {
-                    ret = false;
-                    break;
-                }
-            } else {
-                buffer_append(sctx, s);
-            }
-        } while (time(NULL) - rstart < 60 && !strstr(sctx->sockbuf, "\n"));
-
-        if (!ret) {
-            applog(LOG_ERR, "stratum_recv_line failed");
-            return NULL;
-        }
-    }
-
-    ssize_t buflen = strlen(sctx->sockbuf);
-    char *tok = strtok(sctx->sockbuf, "\n");
-
-    if (!tok) {
-        applog(LOG_ERR, "stratum_recv_line failed to parse a newline-terminated string");
-        return NULL;
-    }
-
-    char *sret = strdup(tok);
-    ssize_t len = strlen(sret);
-
-    if (buflen > len + 1) {
-        memmove(sctx->sockbuf, sctx->sockbuf + len + 1, buflen - len + 1);
-    }
-    else {
-        sctx->sockbuf[0] = '\0';
-    }
-
-    return sret;
-}
-
-
-/**
- * @brief stratum_disconnect
- * @param sctx
- */
-void stratum_disconnect(struct stratum_ctx *sctx)
-{
-    pthread_mutex_lock(&sctx->sock_lock);
-
-    sctx->ready = false;
-
-    if (sctx->curl) {
-        curl_easy_cleanup(sctx->curl);
-        sctx->curl = NULL;
-        sctx->sockbuf[0] = '\0';
-    }
-
-    pthread_mutex_unlock(&sctx->sock_lock);
-}
-
-
-/**
- * @brief stratum_handle_method
- * @param sctx
- * @param s
- * @return
- */
-bool stratum_handle_method(struct stratum_ctx *sctx, const char *s)
-{
-    bool ret = false;
-    const char *method;
-    json_t *val = json_decode(s);
-
-    if (!val) {
-        return false;
-    }
-
-    if (method = json_string_value(json_object_get(val, "method"))) {
-        if (!strcasecmp(method, "job")) {
-            ret = job(sctx, json_object_get(val, "params"));
-        }
-        else {
-            applog(LOG_WARNING, "Unknown method: \"%s\"", method);
-        }
-    }
-
-    json_decref(val);
-    return ret;
-}
-
-
-/**
- * @brief stratum_handle_response
- * @param buf
- * @return
- */
-bool stratum_handle_response(char *buf) {
-    bool valid = false;
-
-    json_t *val = json_decode(buf);
-    if (!val) {
-       return false;
-    }
-
-    json_t *res_val = json_object_get(val, "result");
-    json_t *err_val = json_object_get(val, "error");
-    json_t *id_val = json_object_get(val, "id");
-
-    if (!id_val || json_is_null(id_val) || !res_val) {
-        const char* message;
-
-        if (json_is_object(err_val) && (message = json_string_value(json_object_get(err_val, "message")))) {
-            applog(LOG_ERR, "error: \"%s\"", message);
-        }
-
-        json_decref(val);
-        return false;
-    }
-
-    json_t *status = json_object_get(res_val, "status");
-
-    if (status && !strcmp(json_string_value(status), "KEEPALIVED") ) {
-        applog(LOG_DEBUG, "Keepalived receveid");
-        json_decref(val);
-        return true;
-    }
-
-    if (status) {
-       valid = !strcmp(json_string_value(status), "OK") && json_is_null(err_val);
-    } else {
-       valid = json_is_null(err_val);
-    }
-
-    stats_share_result(valid);
-    json_decref(val);
-    return true;
-}
-
-
-/**
- * @brief stratum_keepalived
- * @param sctx
- * @return
- */
-bool stratum_keepalived(struct stratum_ctx *sctx)
-{
-    char *s = malloc(128);
-    snprintf(s, 128, "{\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"},\"id\":1}", sctx->id);
-    bool ret = stratum_send_line(sctx, s);
-
-    free(s);
-    return ret;
-}
-
-
-/**
- * @brief stratum_authorize
- * @param sctx
- * @param user
- * @param pass
- * @return
- */
-bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass)
-{
-    char *sret;
-
-    char *req = malloc(128 + strlen(user) + strlen(pass));
-    sprintf(req, "{\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"%s/%s\"},\"id\":1}", user, pass, APP_NAME, APP_VERSION);
-
-    if (!stratum_send_line(sctx, req)) {
-        free(req);
-        return false;
-    }
-
-    free(req);
-
-    while (1) {
-        sret = stratum_recv_line(sctx);
-        if (!sret) {
-            return false;
-        }
-
-        if (!stratum_handle_method(sctx, sret)) {
-            break;
-        }
-
-        free(sret);
-    }
-
-    json_t *val = json_decode(sret);
-    free(sret);
-
-    if (!val) {
-        return false;
-    }
-
-    json_t *result = json_object_get(val, "result");
-    json_t *error  = json_object_get(val, "error");
-
-    if (!result || json_is_false(result) || (error && !json_is_null(error)))  {
-        const char* message;
-
-        if (json_is_object(error) && (message = json_string_value(json_object_get(error, "message")))) {
-            applog(LOG_ERR, "Stratum authentication failed: \"%s\"", message);
-        }
-        else {
-            applog(LOG_ERR, "Stratum authentication failed");
-        }
-
-        json_decref(val);
-        return false;
-    }
-
-    if (login_decode(sctx, val) && job(sctx, json_object_get(result, "job"))) {
-        pthread_mutex_lock(&sctx->sock_lock);
-        sctx->ready = true;
-        pthread_mutex_unlock(&sctx->sock_lock);
-    }
-
-    json_decref(val);
-    return true;
-}
-
-
-/**
- * @brief stratum_connect
- * @param sctx
- * @param url
- * @return
- */
-bool stratum_connect(struct stratum_ctx *sctx, const char *url)
-{
-    CURL *curl;
-
-    pthread_mutex_lock(&sctx->sock_lock);
-    sctx->ready = false;
-
-    if (sctx->curl) {
-        curl_easy_cleanup(sctx->curl);
-    }
-
-    sctx->curl = curl_easy_init();
-    if (!sctx->curl) {
-        applog(LOG_ERR, "CURL initialization failed");
-        pthread_mutex_unlock(&sctx->sock_lock);
-        return false;
-    }
-
-    curl = sctx->curl;
-    if (!sctx->sockbuf) {
-        sctx->sockbuf = calloc(RBUFSIZE, 1);
-        sctx->sockbuf_size = RBUFSIZE;
-    }
-
-    sctx->sockbuf[0] = '\0';
-    pthread_mutex_unlock(&sctx->sock_lock);
-
-    if (url != sctx->url) {
-        free(sctx->url);
-        sctx->url = strdup(url);
-    }
-
-    free(sctx->curl_url);
-    sctx->curl_url = malloc(strlen(url));
-    sprintf(sctx->curl_url, "http%s/", strstr(url, "://"));
-
-    curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
-    curl_easy_setopt(curl, CURLOPT_URL, sctx->curl_url);
-    curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
-    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);
-    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, sctx->curl_err_str);
-    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
-    curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
-    curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_keepalive_cb);
-    curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket_grab_cb);
-    curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, closesocket_cb);
-    curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &sctx->sock);
-    curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1);
-    curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
-
-    int rc = curl_easy_perform(curl);
-    if (rc) {
-        applog(LOG_ERR, "Stratum connection failed: code: %d, text: %s", rc, sctx->curl_err_str);
-        curl_easy_cleanup(curl);
-        sctx->curl = NULL;
-        return false;
-    }
-
-    return true;
-}
-
-
-/**
- * @brief send_line
- * @param sock
- * @param s
- * @return
- */
-static bool send_line(curl_socket_t sock, char *s)
-{
-    ssize_t len, sent = 0;
-
-    len = strlen(s);
-    s[len++] = '\n';
-
-    while (len > 0) {
-        struct pollfd pfd;
-        pfd.fd = sock;
-        pfd.events = POLLOUT;
-
-        if (poll(&pfd, 1, 0) < 1) {
-            return false;
-        }
-
-        ssize_t n = send(sock, s + sent, len, 0);
-        if (n < 0) {
-            if (!socket_blocks()) {
-                return false;
-            }
-
-            n = 0;
-        }
-
-        sent += n;
-        len -= n;
-    }
-
-    return true;
-}
-
-
-/**
- * @brief socket_full
- * @param sock
- * @param timeout
- * @return
- */
-static bool socket_full(curl_socket_t sock, int timeout)
-{
-    struct pollfd pfd;
-    pfd.fd = sock;
-    pfd.events = POLLIN;
-
-    return poll(&pfd, 1, timeout * 1000) > 0;
-}
-
-
-/**
- * @brief buffer_append
- * @param sctx
- * @param s
- */
-static void buffer_append(struct stratum_ctx *sctx, const char *s)
-{
-    size_t old, new;
-
-    old = strlen(sctx->sockbuf);
-    new = old + strlen(s) + 1;
-
-    if (new >= sctx->sockbuf_size) {
-        sctx->sockbuf_size = new + (RBUFSIZE - (new % RBUFSIZE));
-        sctx->sockbuf = realloc(sctx->sockbuf, sctx->sockbuf_size);
-    }
-
-    strcpy(sctx->sockbuf + old, s);
-}
-
-
-/**
- * @brief job
- * @param sctx
- * @param params
- * @return
- */
-static bool job(struct stratum_ctx *sctx, json_t *params)
-{
-    if (!job_decode(params)) {
-        return false;
-    }
-
-    pthread_mutex_lock(&sctx->work_lock);
-
-    if (sctx->work.target != work.target) {
-        stats_set_target(work.target);
-    }
-
-    memcpy(&sctx->work, &work, sizeof(struct work));
-    pthread_mutex_unlock(&sctx->work_lock);
-
-    return true;
-}
-
-
-/**
- * @brief sockopt_keepalive_cb
- * @param userdata
- * @param fd
- * @param purpose
- * @return
- */
-static int sockopt_keepalive_cb(void *userdata, curl_socket_t fd, curlsocktype purpose)
-{
-    int keepalive = 1;
-    int tcp_keepcnt = 3;
-    int tcp_keepidle = 50;
-    int tcp_keepintvl = 50;
-
-#ifndef WIN32
-    if (unlikely(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive,
-        sizeof(keepalive))))
-        return 1;
-#ifdef __linux
-    if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPCNT,
-        &tcp_keepcnt, sizeof(tcp_keepcnt))))
-        return 1;
-    if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPIDLE,
-        &tcp_keepidle, sizeof(tcp_keepidle))))
-        return 1;
-    if (unlikely(setsockopt(fd, SOL_TCP, TCP_KEEPINTVL,
-        &tcp_keepintvl, sizeof(tcp_keepintvl))))
-        return 1;
-#endif /* __linux */
-#ifdef __APPLE_CC__
-    if (unlikely(setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE,
-        &tcp_keepintvl, sizeof(tcp_keepintvl))))
-        return 1;
-#endif /* __APPLE_CC__ */
-#else /* WIN32 */
-    struct tcp_keepalive vals;
-    vals.onoff = 1;
-    vals.keepalivetime = tcp_keepidle * 1000;
-    vals.keepaliveinterval = tcp_keepintvl * 1000;
-    DWORD outputBytes;
-    if (unlikely(WSAIoctl(fd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals), NULL, 0, &outputBytes, NULL, NULL))) {
-        return 1;
-    }
-
-#endif /* WIN32 */
-
-    return 0;
-}
-
-
-static int closesocket_cb(void *clientp, curl_socket_t item) {
-    shutdown(item, SHUT_RDWR);
-    return closesocket(item);
-}
-
-
-/**
- * @brief opensocket_grab_cb
- * @param clientp
- * @param purpose
- * @param addr
- * @return
- */
-static curl_socket_t opensocket_grab_cb(void *clientp, curlsocktype purpose, struct curl_sockaddr *addr)
-{
-    curl_socket_t *sock = clientp;
-    *sock = socket(addr->family, addr->socktype, addr->protocol);
-    return *sock;
-}
-
-
-/**
- * @brief login_decode
- * @param sctx
- * @param val
- * @return
- */
-static bool login_decode(struct stratum_ctx *sctx, const json_t *val) {
-    json_t *res = json_object_get(val, "result");
-    if (!res) {
-        applog(LOG_ERR, "JSON invalid result");
-        return false;
-    }
-
-    const char *id = json_string_value(json_object_get(res, "id"));
-    if (!id || strlen(id) >= (sizeof(sctx->id))) {
-        applog(LOG_ERR, "JSON invalid id");
-        return false;
-    }
-
-    memset(&sctx->id, 0, sizeof(sctx->id));
-    memcpy(&sctx->id, id, strlen(id));
-
-    const char *s = json_string_value(json_object_get(res, "status"));
-    if (!s) {
-        applog(LOG_ERR, "JSON invalid status");
-        return false;
-    }
-
-    if (strcmp(s, "OK")) {
-        applog(LOG_ERR, "JSON returned status \"%s\"", s);
-        return false;
-    }
-
-    return true;
-}
-
-
-/**
- * @brief job_decode
- * @param sctx
- * @param job
- * @param work
- * @return
- */
-static bool job_decode(const json_t *job) {
-    const char *job_id = json_string_value(json_object_get(job, "job_id"));
-    if (!job_id || strlen(job_id) >= sizeof(work.job_id)) {
-        applog(LOG_ERR, "JSON invalid job id");
-        return false;
-    }
-
-    const char *blob = json_string_value(json_object_get(job, "blob"));
-    if (!blob) {
-        applog(LOG_ERR, "JSON invalid blob");
-        return false;
-    }
-
-    work.blob_size = strlen(blob);
-    if (work.blob_size % 2 != 0) {
-        applog(LOG_ERR, "JSON invalid blob length");
-        return false;
-    }
-
-    work.blob_size /= 2;
-    if (work.blob_size < 76 || work.blob_size > (sizeof(work.blob))) {
-        applog(LOG_ERR, "JSON invalid blob length");
-        return false;
-    }
-
-    if (!hex2bin((unsigned char *) work.blob, blob, work.blob_size)) {
-        applog(LOG_ERR, "JSON invalid blob");
-        return false;
-    }
-
-    jobj_binary(job, "target", &work.target, 4);
-
-    memset(work.job_id, 0, sizeof(work.job_id));
-    memcpy(work.job_id, job_id, strlen(job_id));
-
-    return true;
-}
-
-
-/**
- * @brief jobj_binary
- * @param obj
- * @param key
- * @param buf
- * @param buflen
- * @return
- */
-static bool jobj_binary(const json_t *obj, const char *key, void *buf, size_t buflen) {
-    const char *hexstr;
-    json_t *tmp;
-
-    tmp = json_object_get(obj, key);
-    if (unlikely(!tmp)) {
-        applog(LOG_ERR, "JSON key '%s' not found", key);
-        return false;
-    }
-
-    hexstr = json_string_value(tmp);
-    if (unlikely(!hexstr)) {
-        applog(LOG_ERR, "JSON key '%s' is not a string", key);
-        return false;
-    }
-
-
-    if (!hex2bin(buf, hexstr, buflen)) {
-        return false;
-    }
-
-    return true;
-}
diff --git a/stratum.h b/stratum.h
deleted file mode 100644
index 483695674..000000000
--- a/stratum.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __STRATUM_H__
-#define __STRATUM_H__
-
-#include <stdbool.h>
-#include <inttypes.h>
-#include <curl/curl.h>
-
-
-/**
- * 128tx exploit.
- *
- * Max blob size is 84 (75 fixed + 9 variable), aligned to 96.
- * https://github.com/xmrig/xmrig/issues/1 Thanks fireice-uk.
- */
-struct work {
-    uint32_t blob[21] __attribute__((aligned(16)));
-    size_t blob_size  __attribute__((aligned(16)));
-    uint32_t target   __attribute__((aligned(16)));
-    uint32_t hash[8]  __attribute__((aligned(16)));
-    char job_id[64]   __attribute__((aligned(16)));
-};
-
-
-struct stratum_ctx {
-    char *url;
-
-    CURL *curl;
-    char *curl_url;
-    char curl_err_str[CURL_ERROR_SIZE];
-    curl_socket_t sock;
-    size_t sockbuf_size;
-    char *sockbuf;
-    pthread_mutex_t sock_lock;
-    bool ready;
-
-    char id[64];
-
-    struct work work;
-    struct work g_work;
-    time_t g_work_time;
-    pthread_mutex_t work_lock;
-};
-
-
-bool stratum_send_line(struct stratum_ctx *sctx, char *s);
-bool stratum_socket_full(struct stratum_ctx *sctx, int timeout);
-char *stratum_recv_line(struct stratum_ctx *sctx);
-bool stratum_connect(struct stratum_ctx *sctx, const char *url);
-void stratum_disconnect(struct stratum_ctx *sctx);
-bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass);
-bool stratum_handle_method(struct stratum_ctx *sctx, const char *s);
-bool stratum_handle_response(char *buf);
-bool stratum_keepalived(struct stratum_ctx *sctx);
-
-#endif /* __STRATUM_H__ */
diff --git a/unix/memory_unix.c b/unix/memory_unix.c
deleted file mode 100644
index fad7f730e..000000000
--- a/unix/memory_unix.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __MEMORY_H__
-#define __MEMORY_H__
-
-#include <stdlib.h>
-#include <mm_malloc.h>
-#include <sys/mman.h>
-
-#include "persistent_memory.h"
-#include "options.h"
-#include "utils/applog.h"
-
-
-char *persistent_memory;
-int persistent_memory_flags = 0;
-
-
-const char * persistent_memory_allocate() {
-    const int ratio = (opt_double_hash && opt_algo != ALGO_CRYPTONIGHT_LITE) ? 2 : 1;
-    const int size = MEMORY * (opt_n_threads * ratio + 1);
-    persistent_memory_flags |= MEMORY_HUGEPAGES_AVAILABLE;
-
-    persistent_memory = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0);
-
-    if (persistent_memory == MAP_FAILED) {
-        persistent_memory = _mm_malloc(size, 4096);
-        return persistent_memory;
-    }
-
-    persistent_memory_flags |= MEMORY_HUGEPAGES_ENABLED;
-
-    if (madvise(persistent_memory, size, MADV_RANDOM | MADV_WILLNEED) != 0) {
-        applog(LOG_ERR, "madvise failed");
-    }
-
-    if (mlock(persistent_memory, size) == 0) {
-        persistent_memory_flags |= MEMORY_LOCK;
-    }
-
-    return persistent_memory;
-}
-
-
-void persistent_memory_free() {
-    const int size = MEMORY * (opt_n_threads + 1);
-
-    if (persistent_memory_flags & MEMORY_HUGEPAGES_ENABLED) {
-        if (persistent_memory_flags & MEMORY_LOCK) {
-            munlock(persistent_memory, size);
-        }
-
-        munmap(persistent_memory, size);
-    }
-    else {
-        _mm_free(persistent_memory);
-    }
-}
-
-
-#endif /* __MEMORY_H__ */
diff --git a/unix/xmrig_unix.c b/unix/xmrig_unix.c
deleted file mode 100644
index cd25934a1..000000000
--- a/unix/xmrig_unix.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdlib.h>
-#include <signal.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "options.h"
-#include "cpu.h"
-#include "utils/applog.h"
-
-
-static void signal_handler(int sig)
-{
-    switch (sig) {
-    case SIGHUP:
-        applog(LOG_WARNING, "SIGHUP received");
-        break;
-
-    case SIGINT:
-        applog(LOG_WARNING, "SIGINT received, exiting");
-        proper_exit(0);
-        break;
-
-    case SIGTERM:
-        applog(LOG_WARNING, "SIGTERM received, exiting");
-        proper_exit(0);
-        break;
-    }
-}
-
-
-void proper_exit(int reason) {
-    exit(reason);
-}
-
-
-void os_specific_init()
-{
-    if (opt_affinity != -1) {
-        affine_to_cpu_mask(-1, opt_affinity);
-    }
-
-    if (opt_background) {
-        int i = fork();
-        if (i < 0) {
-            exit(1);
-        }
-
-        if (i > 0) {
-            exit(0);
-        }
-
-        i = setsid();
-
-        if (i < 0) {
-            applog(LOG_ERR, "setsid() failed (errno = %d)", errno);
-        }
-
-        i = chdir("/");
-        if (i < 0) {
-            applog(LOG_ERR, "chdir() failed (errno = %d)", errno);
-        }
-
-        signal(SIGHUP, signal_handler);
-        signal(SIGTERM, signal_handler);
-    }
-
-    signal(SIGINT, signal_handler);
-}
diff --git a/util.c b/util.c
deleted file mode 100644
index 3dfec485f..000000000
--- a/util.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <pthread.h>
-
-#include "util.h"
-#include "elist.h"
-#include "utils/applog.h"
-
-
-struct tq_ent {
-    void *data;
-    struct list_head q_node;
-};
-
-
-struct thread_q {
-    struct list_head q;
-    bool frozen;
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
-};
-
-
-json_t *json_decode(const char *s)
-{
-    json_error_t err;
-    json_t *val = json_loads(s, 0, &err);
-
-    if (!val) {
-        applog(LOG_ERR, "JSON decode failed(%d): %s", err.line, err.text);
-    }
-
-    return val;
-}
-
-
-/**
- * @brief bin2hex
- * @param p
- * @param len
- * @return
- */
-char *bin2hex(const unsigned char *p, size_t len)
-{
-    char *s = malloc((len * 2) + 1);
-    if (!s) {
-        return NULL;
-    }
-
-    for (int i = 0; i < len; i++) {
-        sprintf(s + (i * 2), "%02x", (unsigned int) p[i]);
-    }
-
-    return s;
-}
-
-
-/**
- * @brief hex2bin
- * @param p
- * @param hexstr
- * @param len
- * @return
- */
-bool hex2bin(unsigned char *p, const char *hexstr, size_t len)
-{
-    char hex_byte[3];
-    char *ep;
-
-    hex_byte[2] = '\0';
-
-    while (*hexstr && len) {
-        if (!hexstr[1]) {
-            applog(LOG_ERR, "hex2bin str truncated");
-            return false;
-        }
-
-        hex_byte[0] = hexstr[0];
-        hex_byte[1] = hexstr[1];
-        *p = (unsigned char) strtol(hex_byte, &ep, 16);
-        if (*ep) {
-            applog(LOG_ERR, "hex2bin failed on '%s'", hex_byte);
-            return false;
-        }
-
-        p++;
-        hexstr += 2;
-        len--;
-    }
-
-    return (len == 0 && *hexstr == 0) ? true : false;
-}
-
-
-/**
- * @brief tq_new
- * @return
- */
-struct thread_q *tq_new(void)
-{
-    struct thread_q *tq;
-
-    tq = calloc(1, sizeof(*tq));
-    if (!tq)
-        return NULL;
-
-    INIT_LIST_HEAD(&tq->q);
-    pthread_mutex_init(&tq->mutex, NULL);
-    pthread_cond_init(&tq->cond, NULL);
-
-    return tq;
-}
-
-
-/**
- * @brief tq_free
- * @param tq
- */
-void tq_free(struct thread_q *tq)
-{
-    struct tq_ent *ent, *iter;
-
-    if (!tq)
-        return;
-
-    list_for_each_entry_safe(ent, iter, &tq->q, q_node) {
-        list_del(&ent->q_node);
-        free(ent);
-    }
-
-    pthread_cond_destroy(&tq->cond);
-    pthread_mutex_destroy(&tq->mutex);
-
-    memset(tq, 0, sizeof(*tq)); /* poison */
-    free(tq);
-}
-
-
-/**
- * @brief tq_freezethaw
- * @param tq
- * @param frozen
- */
-static void tq_freezethaw(struct thread_q *tq, bool frozen)
-{
-    pthread_mutex_lock(&tq->mutex);
-
-    tq->frozen = frozen;
-
-    pthread_cond_signal(&tq->cond);
-    pthread_mutex_unlock(&tq->mutex);
-}
-
-
-/**
- * @brief tq_freeze
- * @param tq
- */
-void tq_freeze(struct thread_q *tq)
-{
-    tq_freezethaw(tq, true);
-}
-
-
-/**
- * @brief tq_thaw
- * @param tq
- */
-void tq_thaw(struct thread_q *tq)
-{
-    tq_freezethaw(tq, false);
-}
-
-
-/**
- * @brief tq_push
- * @param tq
- * @param data
- * @return
- */
-bool tq_push(struct thread_q *tq, void *data)
-{
-    struct tq_ent *ent;
-    bool rc = true;
-
-    ent = calloc(1, sizeof(*ent));
-    if (!ent)
-        return false;
-
-    ent->data = data;
-    INIT_LIST_HEAD(&ent->q_node);
-
-    pthread_mutex_lock(&tq->mutex);
-
-    if (!tq->frozen) {
-        list_add_tail(&ent->q_node, &tq->q);
-    } else {
-        free(ent);
-        rc = false;
-    }
-
-    pthread_cond_signal(&tq->cond);
-    pthread_mutex_unlock(&tq->mutex);
-
-    return rc;
-}
-
-
-/**
- * @brief tq_pop
- * @param tq
- * @param abstime
- * @return
- */
-void *tq_pop(struct thread_q *tq, const struct timespec *abstime)
-{
-    struct tq_ent *ent;
-    void *rval = NULL;
-    int rc;
-
-    pthread_mutex_lock(&tq->mutex);
-
-    if (!list_empty(&tq->q))
-        goto pop;
-
-    if (abstime)
-        rc = pthread_cond_timedwait(&tq->cond, &tq->mutex, abstime);
-    else
-        rc = pthread_cond_wait(&tq->cond, &tq->mutex);
-    if (rc)
-        goto out;
-    if (list_empty(&tq->q))
-        goto out;
-
-pop:
-    ent = list_entry(tq->q.next, struct tq_ent, q_node);
-    rval = ent->data;
-
-    list_del(&ent->q_node);
-    free(ent);
-
-out:
-    pthread_mutex_unlock(&tq->mutex);
-    return rval;
-}
diff --git a/utils/applog.c b/utils/applog.c
deleted file mode 100644
index e0043c865..000000000
--- a/utils/applog.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "xmrig.h"
-#include "applog.h"
-#include "threads.h"
-#include <sys/time.h>
-#include <string.h>
-
-#ifdef WIN32
-# include "compat/winansi.h"
-#endif
-
-#include "options.h"
-
-
-MUTEX applog_mutex;
-
-
-void applog_init()
-{
-    MUTEX_INIT(applog_mutex);
-}
-
-
-void applog(int prio, const char *fmt, ...)
-{
-    if (opt_background) {
-        return;
-    }
-
-    va_list ap;
-    va_start(ap, fmt);
-
-    struct tm tm;
-    struct tm *tm_p;
-    time_t now = time(NULL);
-
-    MUTEX_LOCK(applog_mutex);
-    tm_p = localtime(&now);
-    memcpy(&tm, tm_p, sizeof(tm));
-    MUTEX_UNLOCK(applog_mutex);
-
-    const char* color = "";
-
-    if (opt_colors) {
-        switch (prio) {
-            case LOG_ERR:     color = CL_RED; break;
-            case LOG_WARNING: color = CL_YLW; break;
-            case LOG_NOTICE:  color = CL_WHT; break;
-            case LOG_INFO:    color = ""; break;
-            case LOG_DEBUG:   color = CL_GRY; break;
-
-            case LOG_BLUE:
-                prio = LOG_NOTICE;
-                color = CL_CYN;
-                break;
-
-            case LOG_GREEN:
-                prio = LOG_NOTICE;
-                color = CL_LGR;
-                break;
-        }
-    }
-
-    const int len = 64 + strlen(fmt) + 2;
-    char *f       = alloca(len);
-
-    sprintf(f, "[%d-%02d-%02d %02d:%02d:%02d]%s %s%s\n",
-            tm.tm_year + 1900,
-            tm.tm_mon + 1,
-            tm.tm_mday,
-            tm.tm_hour,
-            tm.tm_min,
-            tm.tm_sec,
-            color,
-            fmt,
-            opt_colors ? CL_N : ""
-        );
-
-    MUTEX_LOCK(applog_mutex);
-    vfprintf(stderr, f, ap);
-    fflush(stderr);
-    MUTEX_UNLOCK(applog_mutex);
-
-    va_end(ap);
-}
-
-
-void applog_notime(int prio, const char *fmt, ...)
-{
-    if (opt_background) {
-        return;
-    }
-
-    va_list ap;
-    va_start(ap, fmt);
-
-    const char* color = "";
-
-    if (opt_colors) {
-        switch (prio) {
-            case LOG_ERR:     color = CL_RED; break;
-            case LOG_WARNING: color = CL_LYL; break;
-            case LOG_NOTICE:  color = CL_WHT; break;
-            case LOG_INFO:    color = ""; break;
-            case LOG_DEBUG:   color = CL_GRY; break;
-
-            case LOG_BLUE:
-                prio = LOG_NOTICE;
-                color = CL_CYN;
-                break;
-        }
-    }
-
-    const int len = 64 + strlen(fmt) + 2;
-    char *f       = alloca(len);
-
-    sprintf(f, "%s%s%s\n",
-            color,
-            fmt,
-            opt_colors ? CL_N : ""
-        );
-
-    MUTEX_LOCK(applog_mutex);
-    vfprintf(stderr, f, ap);
-    fflush(stderr);
-    MUTEX_UNLOCK(applog_mutex);
-
-    va_end(ap);
-}
diff --git a/utils/applog.h b/utils/applog.h
deleted file mode 100644
index 24a732265..000000000
--- a/utils/applog.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __APPLOG_H__
-#define __APPLOG_H__
-
-enum {
-    LOG_ERR,
-    LOG_WARNING,
-    LOG_NOTICE,
-    LOG_INFO,
-    LOG_DEBUG,
-    LOG_BLUE = 0x10,
-    LOG_GREEN
-};
-
-#define CL_N    "\x1B[0m"
-#define CL_RED  "\x1B[31m"
-#define CL_GRN  "\x1B[32m"
-#define CL_YLW  "\x1B[33m"
-#define CL_BLU  "\x1B[34m"
-#define CL_MAG  "\x1B[35m"
-#define CL_CYN  "\x1B[36m"
-
-#define CL_BLK  "\x1B[22;30m" /* black */
-#define CL_RD2  "\x1B[22;31m" /* red */
-#define CL_GR2  "\x1B[22;32m" /* green */
-#define CL_BRW  "\x1B[22;33m" /* brown */
-#define CL_BL2  "\x1B[22;34m" /* blue */
-#define CL_MA2  "\x1B[22;35m" /* magenta */
-#define CL_CY2  "\x1B[22;36m" /* cyan */
-#define CL_SIL  "\x1B[22;37m" /* gray */
-
-#ifdef WIN32
-#define CL_GRY  "\x1B[01;30m" /* dark gray */
-#else
-#define CL_GRY  "\x1B[90m"    /* dark gray selectable in putty */
-#endif
-#define CL_LRD  "\x1B[01;31m" /* light red */
-#define CL_LGR  "\x1B[01;32m" /* light green */
-#define CL_LYL  "\x1B[01;33m" /* light yellow */
-#define CL_LBL  "\x1B[01;34m" /* light blue */
-#define CL_LMA  "\x1B[01;35m" /* light magenta */
-#define CL_LCY  "\x1B[01;36m" /* light cyan */
-
-#define CL_WHT  "\x1B[01;37m" /* white */
-
-#define OPT_COLOR(color, text) (opt_colors ? (color text CL_N) : text)
-
-
-void applog_init();
-void applog(int prio, const char *fmt, ...);
-void applog_notime(int prio, const char *fmt, ...);
-
-#endif /* __APPLOG_H__ */
diff --git a/utils/summary.c b/utils/summary.c
deleted file mode 100644
index 65912bb0b..000000000
--- a/utils/summary.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "options.h"
-#include "applog.h"
-#include "version.h"
-#include "persistent_memory.h"
-#include "cpu.h"
-
-
-static void print_memory() {
-    const char *t1 = (persistent_memory_flags & MEMORY_HUGEPAGES_AVAILABLE) ? OPT_COLOR(CL_LGR, "available") : OPT_COLOR(CL_LRD, "unavailable");
-    const char *t2 = (persistent_memory_flags & MEMORY_HUGEPAGES_ENABLED)   ? OPT_COLOR(CL_LGR, "enabled")   : OPT_COLOR(CL_LRD, "disabled");
-
-    if (opt_colors) {
-        applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "HUGE PAGES:   %s, %s", t1, t2);
-    }
-    else {
-        applog_notime(LOG_INFO, " * HUGE PAGES:   %s, %s", t1, t2);
-    }
-}
-
-
-static void print_cpu() {
-    const char *t1 = (cpu_info.flags & CPU_FLAG_X86_64) ? OPT_COLOR(CL_LGR, "x86_64") : OPT_COLOR(CL_LRD, "-x86_64");
-    const char *t2 = (cpu_info.flags & CPU_FLAG_AES)    ? OPT_COLOR(CL_LGR, "AES-NI") : OPT_COLOR(CL_LRD, "-AES-NI");
-
-    if (opt_colors) {
-        applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "CPU:          %s (%d)", cpu_info.brand, cpu_info.sockets);
-    }
-    else {
-        applog_notime(LOG_INFO, " * CPU:          %s (%d)", cpu_info.brand, cpu_info.sockets);
-    }
-
- #   ifndef XMRIG_NO_LIBCPUID
-    if (opt_colors) {
-        applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "CPU L2/L3:    %.1f MB/%.1f MB", cpu_info.l2_cache / 1024.0, cpu_info.l3_cache / 1024.0);
-    }
-    else {
-        applog_notime(LOG_INFO, " * CPU L2/L3:    %.1f MB/%.1f MB", cpu_info.l2_cache / 1024.0, cpu_info.l3_cache / 1024.0);
-    }
- #  endif
-
-    if (opt_colors) {
-        applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "CPU FEATURES: %s %s", t1, t2);
-    }
-    else {
-        applog_notime(LOG_INFO, " * CPU FEATURES: %s %s", t1, t2);
-    }
-}
-
-
-static void print_threads() {
-    const char *extra = "";
-    if (opt_nicehash) {
-        extra = ", nicehash";
-    }
-
-    if (opt_colors) {
-        applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "THREADS:      " CL_WHT "%d" CL_WHT ", av=%d, %s, donate=%d%%%s", opt_n_threads, opt_algo_variant, get_current_algo_name(), opt_donate_level, extra);
-    }
-    else {
-        applog_notime(LOG_INFO, " * THREADS:      %d, av=%d, %s, donate=%d%%%s", opt_n_threads, opt_algo_variant, get_current_algo_name(), opt_donate_level, extra);
-    }
-}
-
-
-static void print_stratum() {
-    if (opt_colors) {
-        applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "STRATUM URL:  " CL_LCY "%s", opt_url);
-
-        if (opt_backup_url) {
-            applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "FAILOVER URL: " CL_LCY "%s", opt_backup_url);
-        }
-        else {
-            applog_notime(LOG_INFO, CL_LGR " * " CL_WHT "FAILOVER URL: " CL_LRD "none");
-        }
-    }
-    else {
-        applog_notime(LOG_INFO, " * STRATUM URL:  %s", opt_url);
-        applog_notime(LOG_INFO, " * FAILOVER URL: %s", opt_backup_url ? opt_backup_url : "none");
-    }
-}
-
-
-void print_summary() {
-    if (opt_colors) {
-        applog_notime(LOG_INFO, CL_LGR " * " CL_WHT APP_NAME " " APP_VERSION "   " CL_LCY APP_SITE);
-    }
-    else {
-        applog_notime(LOG_INFO, " * " APP_NAME " " APP_VERSION "   " APP_SITE);
-    }
-
-    print_memory();
-    print_cpu();
-    print_threads();
-    print_stratum();
-}
-
-
-
diff --git a/utils/threads.h b/utils/threads.h
deleted file mode 100644
index a2ef09f39..000000000
--- a/utils/threads.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __THREADS_H__
-#define __THREADS_H__
-
-#if defined(WIN32) && defined(USE_NATIVE_THREADS)
-# include <windows.h>
-# define MUTEX               CRITICAL_SECTION
-# define MUTEX_INIT(mutex)   InitializeCriticalSection(&mutex)
-# define MUTEX_LOCK(mutex)   EnterCriticalSection(&mutex)
-# define MUTEX_UNLOCK(mutex) LeaveCriticalSection(&mutex)
-#else
-# include <pthread.h>
-# define MUTEX               pthread_mutex_t
-# define MUTEX_INIT(mutex)   pthread_mutex_init(&mutex, NULL)
-# define MUTEX_LOCK(mutex)   pthread_mutex_lock(&mutex)
-# define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&mutex)
-#endif
-
-#endif /* __THREADS_H__ */
diff --git a/win/xmrig_win.c b/win/xmrig_win.c
deleted file mode 100644
index 96921faab..000000000
--- a/win/xmrig_win.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- 
-#include <windows.h>
-
-#include "options.h"
-#include "cpu.h"
-#include "utils/applog.h"
-
-
-BOOL WINAPI ConsoleHandler(DWORD dwType)
-{
-    switch (dwType) {
-    case CTRL_C_EVENT:
-        applog(LOG_WARNING, "CTRL_C_EVENT received, exiting");
-        proper_exit(0);
-        break;
-
-    case CTRL_BREAK_EVENT:
-        applog(LOG_WARNING, "CTRL_BREAK_EVENT received, exiting");
-        proper_exit(0);
-        break;
-
-    default:
-        return false;
-}
-
-    return true;
-}
-
-
-void proper_exit(int reason) {
-    if (opt_background) {
-        HWND hcon = GetConsoleWindow();
-        if (hcon) {
-            // unhide parent command line windows
-            ShowWindow(hcon, SW_SHOWMINNOACTIVE);
-        }
-    }
-
-    exit(reason);
-}
-
-
-void os_specific_init()
-{
-    if (opt_affinity != -1) {
-        affine_to_cpu_mask(-1, opt_affinity);
-    }
-
-    SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE);
-
-    if (opt_background) {
-        HWND hcon = GetConsoleWindow();
-        if (hcon) {
-            // this method also hide parent command line window
-            ShowWindow(hcon, SW_HIDE);
-        } else {
-            HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
-            CloseHandle(h);
-            FreeConsole();
-        }
-    }
-}
diff --git a/xmrig.c b/xmrig.c
deleted file mode 100644
index d3c423a50..000000000
--- a/xmrig.c
+++ /dev/null
@@ -1,677 +0,0 @@
-/* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2017 XMRig       <support@xmrig.com>
- *
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include <unistd.h>
-#include <jansson.h>
-#include <sys/time.h>
-
-#ifdef WIN32
-#   include <winsock2.h>
-#   include <windows.h>
-#endif
-
-#include <jansson.h>
-#include <curl/curl.h>
-#include <pthread.h>
-
-#include "compat.h"
-#include "xmrig.h"
-#include "algo/cryptonight/cryptonight.h"
-#include "options.h"
-#include "cpu.h"
-#include "persistent_memory.h"
-#include "stratum.h"
-#include "stats.h"
-#include "util.h"
-#include "utils/summary.h"
-#include "utils/applog.h"
-
-#define LP_SCANTIME  60
-#define JSON_BUF_LEN 345
-
-
-struct workio_cmd {
-    struct thr_info *thr;
-    struct work *work;
-};
-
-
-struct thr_info *thr_info;
-static int work_thr_id = -1;
-static int timer_thr_id = -1;
-static int stratum_thr_id = -1;
-struct work_restart *work_restart = NULL;
-static struct stratum_ctx *stratum_ctx = NULL;
-static bool backup_active = false;
-static bool g_want_donate = false;
-
-
-static void workio_cmd_free(struct workio_cmd *wc);
-
-
-/**
- * @brief work_copy
- * @param dest
- * @param src
- */
-static inline void work_copy(struct work *dest, const struct work *src) {
-    memcpy(dest, src, sizeof(struct work));
-}
-
-
-/**
- * @brief restart_threads
- */
-static inline void restart_threads(void) {
-    for (int i = 0; i < opt_n_threads; i++) {
-        work_restart[i].restart = 1;
-    }
-}
-
-
-/**
- * @brief gen_workify
- * @param sctx
- * @param work
- */
-static inline void gen_workify(struct stratum_ctx *sctx) {
-    pthread_mutex_lock(&stratum_ctx->work_lock);
-
-    if (stratum_ctx->work.job_id && (!stratum_ctx->g_work_time || strcmp(stratum_ctx->work.job_id, stratum_ctx->g_work.job_id))) {
-        memcpy(&sctx->g_work, &sctx->work, sizeof(struct work));
-        time(&stratum_ctx->g_work_time);
-
-        pthread_mutex_unlock(&stratum_ctx->work_lock);
-
-        applog(LOG_DEBUG, "Stratum detected new block");
-        restart_threads();
-
-        return;
-    }
-
-    pthread_mutex_unlock(&stratum_ctx->work_lock);
-}
-
-
-/**
- * @brief submit_upstream_work
- * @param work
- * @return
- */
-static bool submit_upstream_work(struct work *work) {
-    char s[JSON_BUF_LEN];
-
-    /* pass if the previous hash is not the current previous hash */
-    if (memcmp(work->blob + 1, stratum_ctx->g_work.blob + 1, 32)) {
-        return true;
-    }
-
-    char *noncestr = bin2hex(((const unsigned char*) work->blob) + 39, 4);
-    char *hashhex  = bin2hex((const unsigned char *) work->hash, 32);
-
-    snprintf(s, JSON_BUF_LEN,
-            "{\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"},\"id\":1}",
-            stratum_ctx->id, work->job_id, noncestr, hashhex);
-
-    free(hashhex);
-    free(noncestr);
-
-    if (unlikely(!stratum_send_line(stratum_ctx, s))) {
-        return false;
-    }
-
-    return true;
-}
-
-
-
-/**
- * @brief workio_cmd_free
- * @param wc
- */
-static void workio_cmd_free(struct workio_cmd *wc) {
-    if (!wc) {
-        return;
-    }
-
-    free(wc->work);
-
-    memset(wc, 0, sizeof(*wc)); /* poison */
-    free(wc);
-}
-
-
-/**
- * @brief workio_submit_work
- * @param wc
- * @param curl
- * @return
- */
-static bool workio_submit_work(struct workio_cmd *wc) {
-    while (!submit_upstream_work(wc->work)) {
-        sleep(opt_retry_pause);
-    }
-
-    return true;
-}
-
-
-/**
- * @brief workio_thread
- * @param userdata
- * @return
- */
-static void *workio_thread(void *userdata) {
-    struct thr_info *mythr = userdata;
-    bool ok = true;
-
-    while (ok) {
-        struct workio_cmd *wc;
-
-        /* wait for workio_cmd sent to us, on our queue */
-        wc = tq_pop(mythr->q, NULL );
-        if (!wc) {
-            ok = false;
-            break;
-        }
-
-        workio_submit_work(wc);
-        workio_cmd_free(wc);
-    }
-
-    tq_freeze(mythr->q);
-
-    return NULL ;
-}
-
-
-/**
- * @brief submit_work
- * @param thr
- * @param work_in
- * @return
- */
-static bool submit_work(struct thr_info *thr, const struct work *work_in) {
-    struct workio_cmd *wc;
-
-    /* fill out work request message */
-    wc = calloc(1, sizeof(*wc));
-    wc->work = malloc(sizeof(*work_in));
-
-    if (likely(wc->work)) {
-        wc->thr = thr;
-        work_copy(wc->work, work_in);
-
-        if (likely(tq_push(thr_info[work_thr_id].q, wc))) {
-            return true;
-        }
-    }
-
-    workio_cmd_free(wc);
-    return false;
-}
-
-
-static bool should_pause(int thr_id) {
-    bool ret = false;
-
-    pthread_mutex_lock(&stratum_ctx->sock_lock);
-
-    if (!stratum_ctx->ready) {
-        ret = true;
-    }
-
-    pthread_mutex_unlock(&stratum_ctx->sock_lock);
-
-    return ret;
-}
-
-
-/**
- * @brief miner_thread
- * @param userdata
- * @return
- */
-static void *miner_thread(void *userdata) {
-    struct thr_info *mythr = userdata;
-    const int thr_id = mythr->id;
-    struct work work = { { 0 } };
-    uint32_t max_nonce;
-    uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - 0x20;
-
-    struct cryptonight_ctx *persistentctx = (struct cryptonight_ctx *) create_persistent_ctx(thr_id);
-
-    if (cpu_info.total_logical_cpus > 1 && opt_affinity != -1L) {
-        affine_to_cpu_mask(thr_id, (unsigned long) opt_affinity);
-    }
-
-    uint32_t *nonceptr = NULL;
-    uint32_t hash[8] __attribute__((aligned(32)));
-
-    while (1) {
-        if (should_pause(thr_id)) {
-            sleep(1);
-            continue;
-        }
-
-        pthread_mutex_lock(&stratum_ctx->work_lock);
-
-        if (memcmp(work.job_id, stratum_ctx->g_work.job_id, 64)) {
-            work_copy(&work, &stratum_ctx->g_work);
-            nonceptr = (uint32_t*) (((char*) work.blob) + 39);
-
-            if (opt_nicehash) {
-                end_nonce = (*nonceptr & 0xff000000U) + (0xffffffU / opt_n_threads * (thr_id + 1) - 0x20);
-                *nonceptr = (*nonceptr & 0xff000000U) + (0xffffffU / opt_n_threads * thr_id);
-            }
-            else {
-                *nonceptr = 0xffffffffU / opt_n_threads * thr_id;
-            }
-        }
-
-        pthread_mutex_unlock(&stratum_ctx->work_lock);
-
-        work_restart[thr_id].restart = 0;
-
-        if (*nonceptr + LP_SCANTIME > end_nonce) {
-            max_nonce = end_nonce;
-        } else {
-            max_nonce = *nonceptr + LP_SCANTIME;
-        }
-
-        unsigned long hashes_done = 0;
-
-        struct timeval tv_start;
-        gettimeofday(&tv_start, NULL);
-
-        /* scan nonces for a proof-of-work hash */
-        const int rc = scanhash_cryptonight(thr_id, hash, work.blob, work.blob_size, work.target, max_nonce, &hashes_done, persistentctx);
-        stats_add_hashes(thr_id, &tv_start, hashes_done);
-
-        if (!rc) {
-            continue;
-        }
-
-        memcpy(work.hash, hash, 32);
-        submit_work(mythr, &work);
-        ++(*nonceptr);
-    }
-
-    tq_freeze(mythr->q);
-    return NULL;
-}
-
-
-/**
- * @brief miner_thread_double
- * @param userdata
- * @return
- */
-static void *miner_thread_double(void *userdata) {
-    struct thr_info *mythr = userdata;
-    const int thr_id = mythr->id;
-    struct work work = { { 0 } };
-    uint32_t max_nonce;
-    uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - 0x20;
-
-    struct cryptonight_ctx *persistentctx = (struct cryptonight_ctx *) create_persistent_ctx(thr_id);
-
-    if (cpu_info.total_logical_cpus > 1 && opt_affinity != -1L) {
-        affine_to_cpu_mask(thr_id, (unsigned long) opt_affinity);
-    }
-
-    uint32_t *nonceptr0 = NULL;
-    uint32_t *nonceptr1 = NULL;
-    uint8_t double_hash[64];
-    uint8_t double_blob[sizeof(work.blob) * 2];
-
-    while (1) {
-        if (should_pause(thr_id)) {
-            sleep(1);
-            continue;
-        }
-
-        pthread_mutex_lock(&stratum_ctx->work_lock);
-
-        if (memcmp(work.job_id, stratum_ctx->g_work.job_id, 64)) {
-            work_copy(&work, &stratum_ctx->g_work);
-
-            memcpy(double_blob,                  work.blob, work.blob_size);
-            memcpy(double_blob + work.blob_size, work.blob, work.blob_size);
-
-            nonceptr0 = (uint32_t*) (((char*) double_blob) + 39);
-            nonceptr1 = (uint32_t*) (((char*) double_blob) + 39 + work.blob_size);
-
-            if (opt_nicehash) {
-                end_nonce = (*nonceptr0 & 0xff000000U) + (0xffffffU / (opt_n_threads * 2) * (thr_id + 1) - 0x20);
-                *nonceptr0 = (*nonceptr0 & 0xff000000U) + (0xffffffU / (opt_n_threads * 2) * thr_id);
-                *nonceptr1 = (*nonceptr1 & 0xff000000U) + (0xffffffU / (opt_n_threads * 2) * (thr_id + opt_n_threads));
-            }
-            else {
-                *nonceptr0 = 0xffffffffU / (opt_n_threads * 2) * thr_id;
-                *nonceptr1 = 0xffffffffU / (opt_n_threads * 2) * (thr_id + opt_n_threads);
-            }
-        }
-
-        pthread_mutex_unlock(&stratum_ctx->work_lock);
-
-        work_restart[thr_id].restart = 0;
-
-        if (*nonceptr0 + (LP_SCANTIME / 2) > end_nonce) {
-            max_nonce = end_nonce;
-        } else {
-            max_nonce = *nonceptr0 + (LP_SCANTIME / 2);
-        }
-
-        unsigned long hashes_done = 0;
-
-        struct timeval tv_start;
-        gettimeofday(&tv_start, NULL);
-
-        /* scan nonces for a proof-of-work hash */
-        const int rc = scanhash_cryptonight_double(thr_id, (uint32_t *) double_hash, double_blob, work.blob_size, work.target, max_nonce, &hashes_done, persistentctx);
-        stats_add_hashes(thr_id, &tv_start, hashes_done);
-
-        if (!rc) {
-            continue;
-        }
-
-        if (rc & 1) {
-            memcpy(work.hash, double_hash, 32);
-            memcpy(work.blob, double_blob, work.blob_size);
-            submit_work(mythr, &work);
-        }
-
-        if (rc & 2) {
-            memcpy(work.hash, double_hash + 32, 32);
-            memcpy(work.blob, double_blob + work.blob_size, work.blob_size);
-            submit_work(mythr, &work);
-        }
-
-        ++(*nonceptr0);
-        ++(*nonceptr1);
-    }
-
-    tq_freeze(mythr->q);
-    return NULL;
-}
-
-
-
-/**
- * @brief stratum_thread
- * @param userdata
- * @return
- */
-static void *timer_thread(void *userdata) {
-    const int max_user_time  = 100 - opt_donate_level;
-    int user_time_remaning   = max_user_time;
-    int donate_time_remaning = 0;
-
-
-    while (1) {
-        sleep(60);
-
-        if (user_time_remaning > 0) {
-            if (--user_time_remaning == 0) {
-                g_want_donate = true;
-
-                donate_time_remaning = opt_donate_level;
-                stratum_disconnect(stratum_ctx);
-                continue;
-            }
-        }
-
-        if (donate_time_remaning > 0) {
-            if (--donate_time_remaning == 0) {
-                g_want_donate = false;
-
-                user_time_remaning = max_user_time;
-                stratum_disconnect(stratum_ctx);
-                continue;
-            }
-        }
-    }
-}
-
-
-static void switch_stratum() {
-    static bool want_donate = false;
-
-    if (g_want_donate && !want_donate) {
-        stratum_ctx->url = opt_algo == ALGO_CRYPTONIGHT ? "stratum+tcp://donate.xmrig.com:443" : "stratum+tcp://donate.xmrig.com:3333";
-        applog(LOG_NOTICE, "Switching to dev pool");
-        want_donate = true;
-    }
-
-    if (!g_want_donate && want_donate) {
-        stratum_ctx->url = backup_active ? opt_backup_url : opt_url;
-        applog(LOG_NOTICE, "Switching to user pool: \"%s\"", stratum_ctx->url);
-        want_donate = false;
-    }
-}
-
-
-
-/**
- * @brief stratum_thread
- * @param userdata
- * @return
- */
-static void *stratum_thread(void *userdata) {
-    char *s;
-
-    stratum_ctx->url   = opt_url;
-    stratum_ctx->ready = false;
-
-    while (1) {
-        int failures = 0;
-        switch_stratum();
-
-        while (!stratum_ctx->curl) {
-            pthread_mutex_lock(&stratum_ctx->work_lock);
-            stratum_ctx->g_work_time = 0;
-            pthread_mutex_unlock(&stratum_ctx->work_lock);
-
-            restart_threads();
-            switch_stratum();
-
-            if (!stratum_connect(stratum_ctx, stratum_ctx->url) || !stratum_authorize(stratum_ctx, opt_user, opt_pass)) {
-                stratum_disconnect(stratum_ctx);
-                failures++;
-
-                if (failures > opt_retries && opt_backup_url) {
-                    failures = 0;
-
-                    backup_active = !backup_active;
-                    stratum_ctx->url = backup_active ? opt_backup_url : opt_url;
-                    sleep(opt_retry_pause);
-
-                    applog(LOG_WARNING, "Switch to: \"%s\"", stratum_ctx->url);
-                    continue;
-                }
-
-                applog(LOG_ERR, "...retry after %d seconds", opt_retry_pause);
-                sleep(opt_retry_pause);
-            }
-        }
-
-        gen_workify(stratum_ctx);
-
-        if (opt_keepalive && !stratum_socket_full(stratum_ctx, 90)) {
-            stratum_keepalived(stratum_ctx);
-        }
-
-        if (!stratum_socket_full(stratum_ctx, 300)) {
-            applog(LOG_ERR, "Stratum connection timed out");
-            s = NULL;
-        } else {
-            s = stratum_recv_line(stratum_ctx);
-        }
-
-        if (!s) {
-            stratum_disconnect(stratum_ctx);
-            applog(LOG_ERR, "Stratum connection interrupted");
-            continue;
-        }
-
-        if (!stratum_handle_method(stratum_ctx, s)) {
-            stratum_handle_response(s);
-        }
-
-        free(s);
-    }
-
-    return NULL ;
-}
-
-
-/**
- * @brief start work I/O thread
- * @return
- */
-static bool start_workio() {
-    work_thr_id = opt_n_threads;
-
-    struct thr_info *thr = &thr_info[work_thr_id];
-    thr->id = work_thr_id;
-    thr->q = tq_new();
-
-    if (unlikely(!thr->q || pthread_create(&thr->pth, NULL, workio_thread, thr))) {
-        return false;
-    }
-
-    return true;
-}
-
-
-/**
- * @brief start_stratum
- * @return
- */
-static bool start_stratum() {
-    stratum_thr_id = opt_n_threads + 1;
-
-    stratum_ctx = persistent_calloc(1, sizeof(struct stratum_ctx));
-    pthread_mutex_init(&stratum_ctx->work_lock, NULL);
-    pthread_mutex_init(&stratum_ctx->sock_lock, NULL);
-
-    struct thr_info *thr = &thr_info[stratum_thr_id];
-    thr->id = stratum_thr_id;
-    thr->q = tq_new();
-
-    if (unlikely(!thr->q || pthread_create(&thr->pth, NULL, stratum_thread, thr))) {
-        return false;
-    }
-
-     tq_push(thr_info[stratum_thr_id].q, strdup(opt_url));
-     return true;
-}
-
-
-/**
- * @brief start_timer
- * @return
- */
-static bool start_timer() {
-    timer_thr_id = opt_n_threads + 2;
-
-    if (opt_donate_level < 1) {
-        return true;
-    }
-
-    struct thr_info *thr = &thr_info[timer_thr_id];
-    thr->id = timer_thr_id;
-    thr->q = tq_new();
-
-    if (unlikely(!thr->q || pthread_create(&thr->pth, NULL, timer_thread, thr))) {
-        return false;
-    }
-
-    return true;
-}
-
-
-/**
- * @brief start_mining
- * @return
- */
-static bool start_mining() {
-    for (int i = 0; i < opt_n_threads; i++) {
-        struct thr_info *thr = &thr_info[i];
-
-        thr->id = i;
-        thr->q = tq_new();
-
-        if (unlikely(!thr->q || pthread_create(&thr->pth, NULL, opt_double_hash ? miner_thread_double : miner_thread, thr))) {
-            applog(LOG_ERR, "thread %d create failed", i);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-
-/**
- * @brief main
- * @param argc
- * @param argv
- * @return
- */
-int main(int argc, char *argv[]) {
-    cpu_init();
-    applog_init();
-    parse_cmdline(argc, argv);
-    persistent_memory_allocate();
-    print_summary();
-
-    stats_init();
-    os_specific_init();
-
-    work_restart = persistent_calloc(opt_n_threads, sizeof(*work_restart));
-    thr_info     = persistent_calloc(opt_n_threads + 3, sizeof(struct thr_info));
-
-    if (!start_workio()) {
-        applog(LOG_ERR, "workio thread create failed");
-        return 1;
-    }
-
-    if (!start_stratum()) {
-        applog(LOG_ERR, "stratum thread create failed");
-        return 1;
-    }
-
-    start_timer();
-
-    if (!start_mining()) {
-        return 1;
-    }
-
-    pthread_join(thr_info[work_thr_id].pth, NULL);
-    applog(LOG_INFO, "workio thread dead, exiting.");
-    persistent_memory_free();
-    return 0;
-}
-