mirror of
https://github.com/xmrig/xmrig.git
synced 2025-12-06 15:42:38 -05:00
Compare commits
44 Commits
v6.23.0
...
db5c6d9190
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db5c6d9190 | ||
|
|
e88009d575 | ||
|
|
5115597e7f | ||
|
|
4cdc35f966 | ||
|
|
b02519b9f5 | ||
|
|
a44b21cef3 | ||
|
|
ea832899f2 | ||
|
|
3ecacf0ac2 | ||
|
|
27c8e60919 | ||
|
|
985fe06e8d | ||
|
|
75b63ddde9 | ||
|
|
643b65f2c0 | ||
|
|
116ba1828f | ||
|
|
da5a5674b4 | ||
|
|
6cc4819cec | ||
|
|
a659397c41 | ||
|
|
20acfd0d79 | ||
|
|
da683d8c3e | ||
|
|
255565b533 | ||
|
|
878e83bf59 | ||
|
|
7abf17cb59 | ||
|
|
eeec5ecd10 | ||
|
|
93f5067999 | ||
|
|
dd6671bc59 | ||
|
|
a1ee2fd9d2 | ||
|
|
2619131176 | ||
|
|
1161f230c5 | ||
|
|
d2363ba28b | ||
|
|
1676da1fe9 | ||
|
|
6e4a5a6d94 | ||
|
|
273133aa63 | ||
|
|
c69e30c9a0 | ||
|
|
6a690ba1e9 | ||
|
|
545aef0937 | ||
|
|
9fa66d3242 | ||
|
|
ec286c7fef | ||
|
|
e28d663d80 | ||
|
|
aba1ad8cfc | ||
|
|
bf44ed52e9 | ||
|
|
762c435fa8 | ||
|
|
48faf0a11b | ||
|
|
d125d22d27 | ||
|
|
9f3591ae0d | ||
|
|
6bbbcc71f1 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@ scripts/deps
|
||||
/CMakeLists.txt.user
|
||||
/.idea
|
||||
/src/backend/opencl/cl/cn/cryptonight_gen.cl
|
||||
.vscode
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
# v6.24.0
|
||||
- [#3671](https://github.com/xmrig/xmrig/pull/3671) Fixed detection of L2 cache size for some complex NUMA topologies.
|
||||
- [#3674](https://github.com/xmrig/xmrig/pull/3674) Fixed ARMv7 build.
|
||||
- [#3677](https://github.com/xmrig/xmrig/pull/3677) Fixed auto-config for AMD CPUs with less than 2 MB L3 cache per thread.
|
||||
- [#3678](https://github.com/xmrig/xmrig/pull/3678) Improved IPv6 support: the new default settings use IPv6 equally with IPv4.
|
||||
|
||||
# v6.23.0
|
||||
- [#3668](https://github.com/xmrig/xmrig/issues/3668) Added support for Windows ARM64.
|
||||
- [#3665](https://github.com/xmrig/xmrig/pull/3665) Tweaked auto-config for AMD CPUs with < 2 MB L3 cache per thread.
|
||||
|
||||
@@ -95,7 +95,7 @@ set(HEADERS_CRYPTO
|
||||
src/crypto/common/VirtualMemory.h
|
||||
)
|
||||
|
||||
if (XMRIG_ARM)
|
||||
if (XMRIG_ARM OR XMRIG_RISCV)
|
||||
set(HEADERS_CRYPTO "${HEADERS_CRYPTO}" src/crypto/cn/CryptoNight_arm.h)
|
||||
else()
|
||||
set(HEADERS_CRYPTO "${HEADERS_CRYPTO}" src/crypto/cn/CryptoNight_x86.h)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
XMRig is a high performance, open source, cross platform RandomX, KawPow, CryptoNight and [GhostRider](https://github.com/xmrig/xmrig/tree/master/src/crypto/ghostrider#readme) unified CPU/GPU miner and [RandomX benchmark](https://xmrig.com/benchmark). Official binaries are available for Windows, Linux, macOS and FreeBSD.
|
||||
|
||||
## Mining backends
|
||||
- **CPU** (x86/x64/ARMv7/ARMv8)
|
||||
- **CPU** (x86/x64/ARMv7/ARMv8/RISC-V)
|
||||
- **OpenCL** for AMD GPUs.
|
||||
- **CUDA** for NVIDIA GPUs via external [CUDA plugin](https://github.com/xmrig/xmrig-cuda).
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
if (WITH_ASM AND NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
if (WITH_ASM AND NOT XMRIG_ARM AND NOT XMRIG_RISCV AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(XMRIG_ASM_LIBRARY "xmrig-asm")
|
||||
|
||||
if (CMAKE_C_COMPILER_ID MATCHES MSVC)
|
||||
|
||||
@@ -21,6 +21,19 @@ if (NOT VAES_SUPPORTED)
|
||||
set(WITH_VAES OFF)
|
||||
endif()
|
||||
|
||||
# Detect RISC-V architecture early (before it's used below)
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv64|riscv|rv64)$")
|
||||
set(RISCV_TARGET 64)
|
||||
set(XMRIG_RISCV ON)
|
||||
add_definitions(-DXMRIG_RISCV)
|
||||
message(STATUS "Detected RISC-V 64-bit architecture (${CMAKE_SYSTEM_PROCESSOR})")
|
||||
elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv32|rv32)$")
|
||||
set(RISCV_TARGET 32)
|
||||
set(XMRIG_RISCV ON)
|
||||
add_definitions(-DXMRIG_RISCV)
|
||||
message(STATUS "Detected RISC-V 32-bit architecture (${CMAKE_SYSTEM_PROCESSOR})")
|
||||
endif()
|
||||
|
||||
if (XMRIG_64_BIT AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$")
|
||||
add_definitions(-DRAPIDJSON_SSE2)
|
||||
else()
|
||||
@@ -29,6 +42,45 @@ else()
|
||||
set(WITH_VAES OFF)
|
||||
endif()
|
||||
|
||||
# Disable x86-specific features for RISC-V
|
||||
if (XMRIG_RISCV)
|
||||
set(WITH_SSE4_1 OFF)
|
||||
set(WITH_AVX2 OFF)
|
||||
set(WITH_VAES OFF)
|
||||
|
||||
# default build uses the RV64GC baseline
|
||||
set(RVARCH "rv64gc")
|
||||
|
||||
# for native builds, enable Zba and Zbb if supported by the CPU
|
||||
if(ARCH STREQUAL "native")
|
||||
enable_language(ASM)
|
||||
|
||||
try_run(RANDOMX_ZBA_RUN_FAIL
|
||||
RANDOMX_ZBA_COMPILE_OK
|
||||
${CMAKE_CURRENT_BINARY_DIR}/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/crypto/randomx/tests/riscv64_zba.s
|
||||
COMPILE_DEFINITIONS "-march=rv64gc_zba")
|
||||
|
||||
if (RANDOMX_ZBA_COMPILE_OK AND NOT RANDOMX_ZBA_RUN_FAIL)
|
||||
set(RVARCH "${RVARCH}_zba")
|
||||
message(STATUS "RISC-V zba extension detected")
|
||||
endif()
|
||||
|
||||
try_run(RANDOMX_ZBB_RUN_FAIL
|
||||
RANDOMX_ZBB_COMPILE_OK
|
||||
${CMAKE_CURRENT_BINARY_DIR}/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/crypto/randomx/tests/riscv64_zbb.s
|
||||
COMPILE_DEFINITIONS "-march=rv64gc_zbb")
|
||||
|
||||
if (RANDOMX_ZBB_COMPILE_OK AND NOT RANDOMX_ZBB_RUN_FAIL)
|
||||
set(RVARCH "${RVARCH}_zbb")
|
||||
message(STATUS "RISC-V zbb extension detected")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Using -march=${RVARCH}")
|
||||
endif()
|
||||
|
||||
add_definitions(-DRAPIDJSON_WRITE_DEFAULT_FLAGS=6) # rapidjson::kWriteNanAndInfFlag | rapidjson::kWriteNanAndInfNullFlag
|
||||
|
||||
if (ARM_V8)
|
||||
@@ -40,7 +92,7 @@ endif()
|
||||
if (NOT ARM_TARGET)
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64|armv8-a)$")
|
||||
set(ARM_TARGET 8)
|
||||
elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv7|armv7f|armv7s|armv7k|armv7-a|armv7l|armv7ve)$")
|
||||
elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv7|armv7f|armv7s|armv7k|armv7-a|armv7l|armv7ve|armv8l)$")
|
||||
set(ARM_TARGET 7)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -26,8 +26,13 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ARM8_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARM8_CXX_FLAGS} -flax-vector-conversions")
|
||||
elseif (ARM_TARGET EQUAL 7)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv7-a -mfpu=neon")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv7-a -mfpu=neon -flax-vector-conversions")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv7-a -mfpu=neon -flax-vector-conversions")
|
||||
elseif (XMRIG_RISCV)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${RVARCH}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${RVARCH}")
|
||||
|
||||
add_definitions(-DHAVE_ROTR)
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||
@@ -41,6 +46,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -Wl,--large-address-aware")
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc")
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
||||
endif()
|
||||
@@ -74,6 +81,11 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
||||
elseif (ARM_TARGET EQUAL 7)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon -march=${CMAKE_SYSTEM_PROCESSOR}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=neon -march=${CMAKE_SYSTEM_PROCESSOR}")
|
||||
elseif (XMRIG_RISCV)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${RVARCH}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=${RVARCH}")
|
||||
|
||||
add_definitions(-DHAVE_ROTR)
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||
|
||||
@@ -17,6 +17,10 @@ else()
|
||||
set(XMRIG_OS_LINUX ON)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR CMAKE_SYSTEM_NAME STREQUAL DragonFly)
|
||||
set(XMRIG_OS_FREEBSD ON)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL OpenBSD)
|
||||
set(XMRIG_OS_OPENBSD ON)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
|
||||
set(XMRIG_OS_HAIKU ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -43,6 +47,10 @@ elseif(XMRIG_OS_UNIX)
|
||||
add_definitions(-DXMRIG_OS_LINUX)
|
||||
elseif (XMRIG_OS_FREEBSD)
|
||||
add_definitions(-DXMRIG_OS_FREEBSD)
|
||||
elseif (XMRIG_OS_OPENBSD)
|
||||
add_definitions(-DXMRIG_OS_OPENBSD)
|
||||
elseif (XMRIG_OS_HAIKU)
|
||||
add_definitions(-DXMRIG_OS_HAIKU)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ if (WITH_RANDOMX)
|
||||
src/crypto/randomx/jit_compiler_x86_static.asm
|
||||
src/crypto/randomx/jit_compiler_x86.cpp
|
||||
)
|
||||
elseif (WITH_ASM AND NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
elseif (WITH_ASM AND NOT XMRIG_ARM AND NOT XMRIG_RISCV AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
list(APPEND SOURCES_CRYPTO
|
||||
src/crypto/randomx/jit_compiler_x86_static.S
|
||||
src/crypto/randomx/jit_compiler_x86.cpp
|
||||
@@ -80,6 +80,13 @@ if (WITH_RANDOMX)
|
||||
else()
|
||||
set_property(SOURCE src/crypto/randomx/jit_compiler_a64_static.S PROPERTY LANGUAGE C)
|
||||
endif()
|
||||
elseif (XMRIG_RISCV AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
list(APPEND SOURCES_CRYPTO
|
||||
src/crypto/randomx/jit_compiler_rv64_static.S
|
||||
src/crypto/randomx/jit_compiler_rv64.cpp
|
||||
)
|
||||
# cheat because cmake and ccache hate each other
|
||||
set_property(SOURCE src/crypto/randomx/jit_compiler_rv64_static.S PROPERTY LANGUAGE C)
|
||||
else()
|
||||
list(APPEND SOURCES_CRYPTO
|
||||
src/crypto/randomx/jit_compiler_fallback.cpp
|
||||
@@ -116,7 +123,7 @@ if (WITH_RANDOMX)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WITH_MSR AND NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND (XMRIG_OS_WIN OR XMRIG_OS_LINUX))
|
||||
if (WITH_MSR AND NOT XMRIG_ARM AND NOT XMRIG_RISCV AND CMAKE_SIZEOF_VOID_P EQUAL 8 AND (XMRIG_OS_WIN OR XMRIG_OS_LINUX))
|
||||
add_definitions(/DXMRIG_FEATURE_MSR)
|
||||
add_definitions(/DXMRIG_FIX_RYZEN)
|
||||
message("-- WITH_MSR=ON")
|
||||
|
||||
365
doc/RISCV_PERF_TUNING.md
Normal file
365
doc/RISCV_PERF_TUNING.md
Normal file
@@ -0,0 +1,365 @@
|
||||
# RISC-V Performance Optimization Guide
|
||||
|
||||
This guide provides comprehensive instructions for optimizing XMRig on RISC-V architectures.
|
||||
|
||||
## Build Optimizations
|
||||
|
||||
### Compiler Flags Applied Automatically
|
||||
|
||||
The CMake build now applies aggressive RISC-V-specific optimizations:
|
||||
|
||||
```cmake
|
||||
# RISC-V ISA with extensions
|
||||
-march=rv64gcv_zba_zbb_zbc_zbs
|
||||
|
||||
# Aggressive compiler optimizations
|
||||
-funroll-loops # Unroll loops for ILP (instruction-level parallelism)
|
||||
-fomit-frame-pointer # Free up frame pointer register (RISC-V has limited registers)
|
||||
-fno-common # Better code generation for global variables
|
||||
-finline-functions # Inline more functions for better cache locality
|
||||
-ffast-math # Relaxed FP semantics (safe for mining)
|
||||
-flto # Link-time optimization for cross-module inlining
|
||||
|
||||
# Release build additions
|
||||
-minline-atomics # Inline atomic operations for faster synchronization
|
||||
```
|
||||
|
||||
### Optimal Build Command
|
||||
|
||||
```bash
|
||||
mkdir build && cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
make -j$(nproc)
|
||||
```
|
||||
|
||||
**Expected build time**: 5-15 minutes depending on CPU
|
||||
|
||||
## Runtime Optimizations
|
||||
|
||||
### 1. Memory Configuration (Most Important)
|
||||
|
||||
Enable huge pages to reduce TLB misses and fragmentation:
|
||||
|
||||
#### Enable 2MB Huge Pages
|
||||
```bash
|
||||
# Calculate required huge pages (1 page = 2MB)
|
||||
# For 2 GB dataset: 1024 pages
|
||||
# For cache + dataset: 1536 pages minimum
|
||||
sudo sysctl -w vm.nr_hugepages=2048
|
||||
```
|
||||
|
||||
Verify:
|
||||
```bash
|
||||
grep HugePages /proc/meminfo
|
||||
# Expected: HugePages_Free should be close to nr_hugepages
|
||||
```
|
||||
|
||||
#### Enable 1GB Huge Pages (Optional but Recommended)
|
||||
|
||||
```bash
|
||||
# Run provided helper script
|
||||
sudo ./scripts/enable_1gb_pages.sh
|
||||
|
||||
# Verify 1GB pages are available
|
||||
cat /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages
|
||||
# Should be: >= 1 (one 1GB page)
|
||||
```
|
||||
|
||||
Update config.json:
|
||||
```json
|
||||
{
|
||||
"cpu": {
|
||||
"huge-pages": true
|
||||
},
|
||||
"randomx": {
|
||||
"1gb-pages": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. RandomX Mode Selection
|
||||
|
||||
| Mode | Memory | Init Time | Throughput | Recommendation |
|
||||
|------|--------|-----------|-----------|-----------------|
|
||||
| **light** | 256 MB | 10 sec | Low | Testing, resource-constrained |
|
||||
| **fast** | 2 GB | 2-5 min* | High | Production (with huge pages) |
|
||||
| **auto** | 2 GB | Varies | High | Default (uses fast if possible) |
|
||||
|
||||
*With optimizations; can be 30+ minutes without huge pages
|
||||
|
||||
**For RISC-V, use fast mode with huge pages enabled.**
|
||||
|
||||
### 3. Dataset Initialization Threads
|
||||
|
||||
Optimal thread count = 60-75% of CPU cores (leaves headroom for OS/other tasks)
|
||||
|
||||
```json
|
||||
{
|
||||
"randomx": {
|
||||
"init": 4
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or auto-detect (rewritten for RISC-V):
|
||||
```json
|
||||
{
|
||||
"randomx": {
|
||||
"init": -1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. CPU Affinity (Optional)
|
||||
|
||||
Pin threads to specific cores for better cache locality:
|
||||
|
||||
```json
|
||||
{
|
||||
"cpu": {
|
||||
"rx/0": [
|
||||
{ "threads": 1, "affinity": 0 },
|
||||
{ "threads": 1, "affinity": 1 },
|
||||
{ "threads": 1, "affinity": 2 },
|
||||
{ "threads": 1, "affinity": 3 }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. CPU Governor (Linux)
|
||||
|
||||
Set to performance mode for maximum throughput:
|
||||
|
||||
```bash
|
||||
# Check current governor
|
||||
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
|
||||
|
||||
# Set to performance (requires root)
|
||||
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
|
||||
|
||||
# Verify
|
||||
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
|
||||
# Should output: performance
|
||||
```
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Minimum (Testing)
|
||||
```json
|
||||
{
|
||||
"randomx": {
|
||||
"mode": "light"
|
||||
},
|
||||
"cpu": {
|
||||
"huge-pages": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Recommended (Balanced)
|
||||
```json
|
||||
{
|
||||
"randomx": {
|
||||
"mode": "auto",
|
||||
"init": 4,
|
||||
"1gb-pages": true
|
||||
},
|
||||
"cpu": {
|
||||
"huge-pages": true,
|
||||
"priority": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Maximum Performance (Production)
|
||||
```json
|
||||
{
|
||||
"randomx": {
|
||||
"mode": "fast",
|
||||
"init": -1,
|
||||
"1gb-pages": true,
|
||||
"scratchpad_prefetch_mode": 1
|
||||
},
|
||||
"cpu": {
|
||||
"huge-pages": true,
|
||||
"priority": 3,
|
||||
"yield": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## CLI Equivalents
|
||||
|
||||
```bash
|
||||
# Light mode
|
||||
./xmrig --randomx-mode=light
|
||||
|
||||
# Fast mode with 4 init threads
|
||||
./xmrig --randomx-mode=fast --randomx-init=4
|
||||
|
||||
# Benchmark
|
||||
./xmrig --bench=1M --algo=rx/0
|
||||
|
||||
# Benchmark Wownero variant (1 MB scratchpad)
|
||||
./xmrig --bench=1M --algo=rx/wow
|
||||
|
||||
# Mine to pool
|
||||
./xmrig -o pool.example.com:3333 -u YOUR_WALLET -p x
|
||||
```
|
||||
|
||||
## Performance Diagnostics
|
||||
|
||||
### Check if Vector Extensions are Detected
|
||||
|
||||
Look for `FEATURES:` line in output:
|
||||
```
|
||||
* CPU: ky,x60 (uarch ky,x1)
|
||||
* FEATURES: rv64imafdcv zba zbb zbc zbs
|
||||
```
|
||||
|
||||
- `v`: Vector extension (RVV) ✓
|
||||
- `zba`, `zbb`, `zbc`, `zbs`: Bit manipulation ✓
|
||||
- If missing, make sure build used `-march=rv64gcv_zba_zbb_zbc_zbs`
|
||||
|
||||
### Verify Huge Pages at Runtime
|
||||
|
||||
```bash
|
||||
# Run xmrig with --bench=1M and check output
|
||||
./xmrig --bench=1M
|
||||
|
||||
# Look for line like:
|
||||
# HUGE PAGES 100% 1 / 1 (1024 MB)
|
||||
```
|
||||
|
||||
- Should show 100% for dataset AND threads
|
||||
- If less, increase `vm.nr_hugepages` and reboot
|
||||
|
||||
### Monitor Performance
|
||||
|
||||
```bash
|
||||
# Run benchmark multiple times to find stable hashrate
|
||||
./xmrig --bench=1M --algo=rx/0
|
||||
./xmrig --bench=10M --algo=rx/0
|
||||
./xmrig --bench=100M --algo=rx/0
|
||||
|
||||
# Check system load and memory during mining
|
||||
while true; do free -h; grep HugePages /proc/meminfo; sleep 2; done
|
||||
```
|
||||
|
||||
## Expected Performance
|
||||
|
||||
### Hardware: Orange Pi RV2 (Ky X1, 8 cores @ ~1.5 GHz)
|
||||
|
||||
| Config | Mode | Hashrate | Init Time |
|
||||
|--------|------|----------|-----------|
|
||||
| Scalar (baseline) | fast | 30 H/s | 10 min |
|
||||
| Scalar + huge pages | fast | 33 H/s | 2 min |
|
||||
| RVV (if enabled) | fast | 70-100 H/s | 3 min |
|
||||
|
||||
*Actual results depend on CPU frequency, memory speed, and load*
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Long Initialization Times (30+ minutes)
|
||||
|
||||
**Cause**: Huge pages not enabled, system using swap
|
||||
**Solution**:
|
||||
1. Enable huge pages: `sudo sysctl -w vm.nr_hugepages=2048`
|
||||
2. Reboot: `sudo reboot`
|
||||
3. Reduce mining threads to free memory
|
||||
4. Check available memory: `free -h`
|
||||
|
||||
### Low Hashrate (50% of expected)
|
||||
|
||||
**Cause**: CPU governor set to power-save, no huge pages, high contention
|
||||
**Solution**:
|
||||
1. Set governor to performance: `echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor`
|
||||
2. Enable huge pages
|
||||
3. Reduce number of mining threads
|
||||
4. Check system load: `top` or `htop`
|
||||
|
||||
### Dataset Init Crashes or Hangs
|
||||
|
||||
**Cause**: Insufficient memory, corrupted huge pages
|
||||
**Solution**:
|
||||
1. Disable huge pages temporarily: set `huge-pages: false` in config
|
||||
2. Reduce mining threads
|
||||
3. Reboot and re-enable huge pages
|
||||
4. Try light mode: `--randomx-mode=light`
|
||||
|
||||
### Out of Memory During Benchmark
|
||||
|
||||
**Cause**: Not enough RAM for dataset + cache + threads
|
||||
**Solution**:
|
||||
1. Use light mode: `--randomx-mode=light`
|
||||
2. Reduce mining threads: `--threads=1`
|
||||
3. Increase available memory (kill other processes)
|
||||
4. Check: `free -h` before mining
|
||||
|
||||
## Advanced Tuning
|
||||
|
||||
### Vector Length (VLEN) Detection
|
||||
|
||||
RISC-V vector extension variable length (VLEN) affects performance:
|
||||
|
||||
```bash
|
||||
# Check VLEN on your CPU
|
||||
cat /proc/cpuinfo | grep vlen
|
||||
|
||||
# Expected values:
|
||||
# - 128 bits (16 bytes) = minimum
|
||||
# - 256 bits (32 bytes) = common
|
||||
# - 512 bits (64 bytes) = high performance
|
||||
```
|
||||
|
||||
Larger VLEN generally means better performance for vectorized operations.
|
||||
|
||||
### Prefetch Optimization
|
||||
|
||||
The code automatically optimizes memory prefetching for RISC-V:
|
||||
|
||||
```
|
||||
scratchpad_prefetch_mode: 0 = disabled (slowest)
|
||||
scratchpad_prefetch_mode: 1 = prefetch.r (default, recommended)
|
||||
scratchpad_prefetch_mode: 2 = prefetch.w (experimental)
|
||||
```
|
||||
|
||||
### Memory Bandwidth Saturation
|
||||
|
||||
If experiencing memory bandwidth saturation (high latency):
|
||||
|
||||
1. Reduce mining threads
|
||||
2. Increase L2/L3 cache by mining fewer threads per core
|
||||
3. Enable cache QoS (AMD Ryzen): `cache_qos: true`
|
||||
|
||||
## Building with Custom Flags
|
||||
|
||||
To build with custom RISC-V flags:
|
||||
|
||||
```bash
|
||||
mkdir build && cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_FLAGS="-march=rv64gcv_zba_zbb_zbc_zbs -O3 -funroll-loops -fomit-frame-pointer" \
|
||||
..
|
||||
make -j$(nproc)
|
||||
```
|
||||
|
||||
## Future Optimizations
|
||||
|
||||
- [ ] Zbk* (crypto) support detection and usage
|
||||
- [ ] Optimal VLEN-aware algorithm selection
|
||||
- [ ] Per-core memory affinity (NUMA support)
|
||||
- [ ] Dynamic thread count adjustment based on thermals
|
||||
- [ ] Cross-compile optimizations for various RISC-V cores
|
||||
|
||||
## References
|
||||
|
||||
- [RISC-V Vector Extension Spec](https://github.com/riscv/riscv-v-spec)
|
||||
- [RISC-V Bit Manipulation Spec](https://github.com/riscv/riscv-bitmanip)
|
||||
- [RISC-V Crypto Spec](https://github.com/riscv/riscv-crypto)
|
||||
- [XMRig Documentation](https://xmrig.com/docs)
|
||||
|
||||
---
|
||||
|
||||
For further optimization, enable RVV intrinsics by replacing `sse2rvv.h` with `sse2rvv_optimized.h` in the build.
|
||||
@@ -12,7 +12,7 @@ if grep -E 'AMD Ryzen|AMD EPYC|AuthenticAMD' /proc/cpuinfo > /dev/null;
|
||||
then
|
||||
if grep "cpu family[[:space:]]\{1,\}:[[:space:]]25" /proc/cpuinfo > /dev/null;
|
||||
then
|
||||
if grep "model[[:space:]]\{1,\}:[[:space:]]97" /proc/cpuinfo > /dev/null;
|
||||
if grep "model[[:space:]]\{1,\}:[[:space:]]\(97\|117\)" /proc/cpuinfo > /dev/null;
|
||||
then
|
||||
echo "Detected Zen4 CPU"
|
||||
wrmsr -a 0xc0011020 0x4400000000000
|
||||
|
||||
2
src/3rdparty/argon2/CMakeLists.txt
vendored
2
src/3rdparty/argon2/CMakeLists.txt
vendored
@@ -35,7 +35,7 @@ if (CMAKE_C_COMPILER_ID MATCHES MSVC)
|
||||
add_feature_impl(xop "" HAVE_XOP)
|
||||
add_feature_impl(avx2 "/arch:AVX2" HAVE_AVX2)
|
||||
add_feature_impl(avx512f "/arch:AVX512F" HAVE_AVX512F)
|
||||
elseif (NOT XMRIG_ARM AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
elseif (NOT XMRIG_ARM AND NOT XMRIG_RISCV AND CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
function(add_feature_impl FEATURE GCC_FLAG DEF)
|
||||
add_library(argon2-${FEATURE} STATIC arch/x86_64/lib/argon2-${FEATURE}.c)
|
||||
target_include_directories(argon2-${FEATURE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../)
|
||||
|
||||
2
src/3rdparty/libethash/endian.h
vendored
2
src/3rdparty/libethash/endian.h
vendored
@@ -31,7 +31,7 @@
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define ethash_swap_u32(input_) OSSwapInt32(input_)
|
||||
#define ethash_swap_u64(input_) OSSwapInt64(input_)
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__HAIKU__)
|
||||
#define ethash_swap_u32(input_) bswap32(input_)
|
||||
#define ethash_swap_u64(input_) bswap64(input_)
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
@@ -46,7 +46,12 @@ else()
|
||||
set(CPUID_LIB "")
|
||||
endif()
|
||||
|
||||
if (XMRIG_ARM)
|
||||
if (XMRIG_RISCV)
|
||||
list(APPEND SOURCES_BACKEND_CPU
|
||||
src/backend/cpu/platform/lscpu_riscv.cpp
|
||||
src/backend/cpu/platform/BasicCpuInfo_riscv.cpp
|
||||
)
|
||||
elseif (XMRIG_ARM)
|
||||
list(APPEND SOURCES_BACKEND_CPU src/backend/cpu/platform/BasicCpuInfo_arm.cpp)
|
||||
|
||||
if (XMRIG_OS_WIN)
|
||||
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
ICpuInfo() = default;
|
||||
virtual ~ICpuInfo() = default;
|
||||
|
||||
# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__)
|
||||
# if defined(__x86_64__) || defined(_M_AMD64) || defined (__arm64__) || defined (__aarch64__) || defined(__riscv) && (__riscv_xlen == 64)
|
||||
inline constexpr static bool is64bit() { return true; }
|
||||
# else
|
||||
inline constexpr static bool is64bit() { return false; }
|
||||
|
||||
@@ -250,7 +250,7 @@ xmrig::BasicCpuInfo::BasicCpuInfo() :
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
if (m_model == 0x61) {
|
||||
if ((m_model == 0x61) || (m_model == 0x75)) {
|
||||
m_arch = ARCH_ZEN4;
|
||||
m_msrMod = MSR_MOD_RYZEN_19H_ZEN4;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ protected:
|
||||
inline Vendor vendor() const override { return m_vendor; }
|
||||
inline uint32_t model() const override
|
||||
{
|
||||
# ifndef XMRIG_ARM
|
||||
# if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
|
||||
return m_model;
|
||||
# else
|
||||
return 0;
|
||||
@@ -80,7 +80,7 @@ protected:
|
||||
Vendor m_vendor = VENDOR_UNKNOWN;
|
||||
|
||||
private:
|
||||
# ifndef XMRIG_ARM
|
||||
# if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
|
||||
uint32_t m_procInfo = 0;
|
||||
uint32_t m_family = 0;
|
||||
uint32_t m_model = 0;
|
||||
|
||||
116
src/backend/cpu/platform/BasicCpuInfo_riscv.cpp
Normal file
116
src/backend/cpu/platform/BasicCpuInfo_riscv.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2025 Slayingripper <https://github.com/Slayingripper>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||
* Copyright (c) 2016-2025 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 <array>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
|
||||
|
||||
#include "backend/cpu/platform/BasicCpuInfo.h"
|
||||
#include "base/tools/String.h"
|
||||
#include "3rdparty/rapidjson/document.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
extern String cpu_name_riscv();
|
||||
extern bool has_riscv_vector();
|
||||
extern bool has_riscv_crypto();
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
|
||||
|
||||
xmrig::BasicCpuInfo::BasicCpuInfo() :
|
||||
m_threads(std::thread::hardware_concurrency())
|
||||
{
|
||||
m_units.resize(m_threads);
|
||||
for (int32_t i = 0; i < static_cast<int32_t>(m_threads); ++i) {
|
||||
m_units[i] = i;
|
||||
}
|
||||
|
||||
memcpy(m_brand, "RISC-V", 6);
|
||||
|
||||
auto name = cpu_name_riscv();
|
||||
if (!name.isNull()) {
|
||||
strncpy(m_brand, name.data(), sizeof(m_brand) - 1);
|
||||
}
|
||||
|
||||
// Check for crypto extensions (Zknd/Zkne/Zknh - AES and SHA)
|
||||
m_flags.set(FLAG_AES, has_riscv_crypto());
|
||||
|
||||
// RISC-V typically supports 1GB huge pages
|
||||
m_flags.set(FLAG_PDPE1GB, std::ifstream("/sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages").good());
|
||||
}
|
||||
|
||||
|
||||
const char *xmrig::BasicCpuInfo::backend() const
|
||||
{
|
||||
return "basic/1";
|
||||
}
|
||||
|
||||
|
||||
xmrig::CpuThreads xmrig::BasicCpuInfo::threads(const Algorithm &algorithm, uint32_t) const
|
||||
{
|
||||
# ifdef XMRIG_ALGO_GHOSTRIDER
|
||||
if (algorithm.family() == Algorithm::GHOSTRIDER) {
|
||||
return CpuThreads(threads(), 8);
|
||||
}
|
||||
# endif
|
||||
|
||||
return CpuThreads(threads());
|
||||
}
|
||||
|
||||
|
||||
rapidjson::Value xmrig::BasicCpuInfo::toJSON(rapidjson::Document &doc) const
|
||||
{
|
||||
using namespace rapidjson;
|
||||
auto &allocator = doc.GetAllocator();
|
||||
|
||||
Value out(kObjectType);
|
||||
|
||||
out.AddMember("brand", StringRef(brand()), allocator);
|
||||
out.AddMember("aes", hasAES(), allocator);
|
||||
out.AddMember("avx2", false, allocator);
|
||||
out.AddMember("x64", is64bit(), allocator); // DEPRECATED will be removed in the next major release.
|
||||
out.AddMember("64_bit", is64bit(), allocator);
|
||||
out.AddMember("l2", static_cast<uint64_t>(L2()), allocator);
|
||||
out.AddMember("l3", static_cast<uint64_t>(L3()), allocator);
|
||||
out.AddMember("cores", static_cast<uint64_t>(cores()), allocator);
|
||||
out.AddMember("threads", static_cast<uint64_t>(threads()), allocator);
|
||||
out.AddMember("packages", static_cast<uint64_t>(packages()), allocator);
|
||||
out.AddMember("nodes", static_cast<uint64_t>(nodes()), allocator);
|
||||
out.AddMember("backend", StringRef(backend()), allocator);
|
||||
out.AddMember("msr", "none", allocator);
|
||||
out.AddMember("assembly", "none", allocator);
|
||||
out.AddMember("arch", "riscv64", allocator);
|
||||
|
||||
Value flags(kArrayType);
|
||||
|
||||
if (hasAES()) {
|
||||
flags.PushBack("aes", allocator);
|
||||
}
|
||||
|
||||
out.AddMember("flags", flags, allocator);
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ static inline size_t countByType(hwloc_topology_t topology, hwloc_obj_type_t typ
|
||||
}
|
||||
|
||||
|
||||
#ifndef XMRIG_ARM
|
||||
#if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
|
||||
static inline std::vector<hwloc_obj_t> findByType(hwloc_obj_t obj, hwloc_obj_type_t type)
|
||||
{
|
||||
std::vector<hwloc_obj_t> out;
|
||||
@@ -207,7 +207,7 @@ bool xmrig::HwlocCpuInfo::membind(hwloc_const_bitmap_t nodeset)
|
||||
|
||||
xmrig::CpuThreads xmrig::HwlocCpuInfo::threads(const Algorithm &algorithm, uint32_t limit) const
|
||||
{
|
||||
# ifndef XMRIG_ARM
|
||||
# if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
|
||||
if (L2() == 0 && L3() == 0) {
|
||||
return BasicCpuInfo::threads(algorithm, limit);
|
||||
}
|
||||
@@ -277,7 +277,7 @@ xmrig::CpuThreads xmrig::HwlocCpuInfo::allThreads(const Algorithm &algorithm, ui
|
||||
|
||||
void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorithm &algorithm, CpuThreads &threads, size_t limit) const
|
||||
{
|
||||
# ifndef XMRIG_ARM
|
||||
# if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
|
||||
constexpr size_t oneMiB = 1024U * 1024U;
|
||||
|
||||
size_t PUs = countByType(cache, HWLOC_OBJ_PU);
|
||||
@@ -311,17 +311,17 @@ void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorith
|
||||
uint32_t intensity = algorithm.maxIntensity() == 1 ? 0 : 1;
|
||||
|
||||
if (cache->attr->cache.depth == 3) {
|
||||
for (size_t i = 0; i < cache->arity; ++i) {
|
||||
hwloc_obj_t l2 = cache->children[i];
|
||||
auto process_L2 = [&L2, &L2_associativity, L3_exclusive, this, &extra, scratchpad](hwloc_obj_t l2) {
|
||||
if (!hwloc_obj_type_is_cache(l2->type) || l2->attr == nullptr) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
L2 += l2->attr->cache.size;
|
||||
L2_associativity = l2->attr->cache.associativity;
|
||||
|
||||
if (L3_exclusive) {
|
||||
if (vendor() == VENDOR_AMD) {
|
||||
if ((vendor() == VENDOR_AMD) && ((arch() == ARCH_ZEN4) || (arch() == ARCH_ZEN5))) {
|
||||
// Use extra L2 only on newer CPUs because older CPUs (Zen 3 and older) don't benefit from it.
|
||||
// For some reason, AMD CPUs can use only half of the exclusive L2/L3 cache combo efficiently
|
||||
extra += std::min<size_t>(l2->attr->cache.size / 2, scratchpad);
|
||||
}
|
||||
@@ -329,6 +329,18 @@ void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorith
|
||||
extra += scratchpad;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < cache->arity; ++i) {
|
||||
hwloc_obj_t ch = cache->children[i];
|
||||
if (ch->type == HWLOC_OBJ_GROUP) {
|
||||
for (size_t j = 0; j < ch->arity; ++j) {
|
||||
process_L2(ch->children[j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
process_L2(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
140
src/backend/cpu/platform/lscpu_riscv.cpp
Normal file
140
src/backend/cpu/platform/lscpu_riscv.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2025 Slayingripper <https://github.com/Slayingripper>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 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 "base/tools/String.h"
|
||||
#include "3rdparty/fmt/core.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
struct riscv_cpu_desc
|
||||
{
|
||||
String model;
|
||||
String isa;
|
||||
String uarch;
|
||||
bool has_vector = false;
|
||||
bool has_crypto = false;
|
||||
|
||||
inline bool isReady() const { return !model.isNull(); }
|
||||
};
|
||||
|
||||
static bool lookup_riscv(char *line, const char *pattern, String &value)
|
||||
{
|
||||
char *p = strstr(line, pattern);
|
||||
if (!p) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p += strlen(pattern);
|
||||
while (isspace(*p)) {
|
||||
++p;
|
||||
}
|
||||
|
||||
if (*p == ':') {
|
||||
++p;
|
||||
}
|
||||
|
||||
while (isspace(*p)) {
|
||||
++p;
|
||||
}
|
||||
|
||||
// Remove trailing newline
|
||||
size_t len = strlen(p);
|
||||
if (len > 0 && p[len - 1] == '\n') {
|
||||
p[len - 1] = '\0';
|
||||
}
|
||||
|
||||
// Ensure we call the const char* assignment (which performs a copy)
|
||||
// instead of the char* overload (which would take ownership of the pointer)
|
||||
value = (const char*)p;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_riscv_cpuinfo(riscv_cpu_desc *desc)
|
||||
{
|
||||
auto fp = fopen("/proc/cpuinfo", "r");
|
||||
if (!fp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buf[2048]; // Larger buffer for long ISA strings
|
||||
while (fgets(buf, sizeof(buf), fp) != nullptr) {
|
||||
lookup_riscv(buf, "model name", desc->model);
|
||||
|
||||
if (lookup_riscv(buf, "isa", desc->isa)) {
|
||||
// Check for vector extensions
|
||||
if (strstr(buf, "zve") || strstr(buf, "v_")) {
|
||||
desc->has_vector = true;
|
||||
}
|
||||
// Check for crypto extensions (AES, SHA, etc.)
|
||||
// zkn* = NIST crypto suite, zks* = SM crypto suite
|
||||
// Note: zba/zbb/zbc/zbs are bit-manipulation, NOT crypto
|
||||
if (strstr(buf, "zknd") || strstr(buf, "zkne") || strstr(buf, "zknh") ||
|
||||
strstr(buf, "zksed") || strstr(buf, "zksh")) {
|
||||
desc->has_crypto = true;
|
||||
}
|
||||
}
|
||||
|
||||
lookup_riscv(buf, "uarch", desc->uarch);
|
||||
|
||||
if (desc->isReady() && !desc->isa.isNull()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return desc->isReady();
|
||||
}
|
||||
|
||||
String cpu_name_riscv()
|
||||
{
|
||||
riscv_cpu_desc desc;
|
||||
if (read_riscv_cpuinfo(&desc)) {
|
||||
if (!desc.uarch.isNull()) {
|
||||
return fmt::format("{} ({})", desc.model, desc.uarch).c_str();
|
||||
}
|
||||
return desc.model;
|
||||
}
|
||||
|
||||
return "RISC-V";
|
||||
}
|
||||
|
||||
bool has_riscv_vector()
|
||||
{
|
||||
riscv_cpu_desc desc;
|
||||
if (read_riscv_cpuinfo(&desc)) {
|
||||
return desc.has_vector;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_riscv_crypto()
|
||||
{
|
||||
riscv_cpu_desc desc;
|
||||
if (read_riscv_cpuinfo(&desc)) {
|
||||
return desc.has_crypto;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace xmrig
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -71,11 +71,11 @@ char *xmrig::Platform::createUserAgent()
|
||||
|
||||
|
||||
#ifndef XMRIG_FEATURE_HWLOC
|
||||
#ifdef __DragonFly__
|
||||
#if defined(__DragonFly__) || defined(XMRIG_OS_OPENBSD) || defined(XMRIG_OS_HAIKU)
|
||||
|
||||
bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id)
|
||||
{
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -18,14 +18,12 @@
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include "getopt/getopt.h"
|
||||
#else
|
||||
# include <getopt.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "base/kernel/config/BaseTransform.h"
|
||||
#include "base/io/json/JsonChain.h"
|
||||
#include "base/io/log/Log.h"
|
||||
@@ -37,7 +35,6 @@
|
||||
#include "base/net/stratum/Pools.h"
|
||||
#include "core/config/Config_platform.h"
|
||||
|
||||
|
||||
#ifdef XMRIG_FEATURE_TLS
|
||||
# include "base/net/tls/TlsConfig.h"
|
||||
#endif
|
||||
@@ -47,9 +44,9 @@ void xmrig::BaseTransform::load(JsonChain &chain, Process *process, IConfigTrans
|
||||
{
|
||||
using namespace rapidjson;
|
||||
|
||||
int key = 0;
|
||||
int argc = process->arguments().argc();
|
||||
char **argv = process->arguments().argv();
|
||||
int key = 0;
|
||||
const int argc = process->arguments().argc();
|
||||
char **argv = process->arguments().argv();
|
||||
|
||||
Document doc(kObjectType);
|
||||
|
||||
@@ -262,7 +259,8 @@ void xmrig::BaseTransform::transform(rapidjson::Document &doc, int key, const ch
|
||||
case IConfig::DaemonKey: /* --daemon */
|
||||
case IConfig::SubmitToOriginKey: /* --submit-to-origin */
|
||||
case IConfig::VerboseKey: /* --verbose */
|
||||
case IConfig::DnsIPv6Key: /* --dns-ipv6 */
|
||||
case IConfig::DnsIPv4Key: /* --ipv4 */
|
||||
case IConfig::DnsIPv6Key: /* --ipv6 */
|
||||
return transformBoolean(doc, key, true);
|
||||
|
||||
case IConfig::ColorKey: /* --no-color */
|
||||
@@ -323,8 +321,11 @@ void xmrig::BaseTransform::transformBoolean(rapidjson::Document &doc, int key, b
|
||||
case IConfig::NoTitleKey: /* --no-title */
|
||||
return set(doc, BaseConfig::kTitle, enable);
|
||||
|
||||
case IConfig::DnsIPv6Key: /* --dns-ipv6 */
|
||||
return set(doc, DnsConfig::kField, DnsConfig::kIPv6, enable);
|
||||
case IConfig::DnsIPv4Key: /* --ipv4 */
|
||||
return set(doc, DnsConfig::kField, DnsConfig::kIPv, 4);
|
||||
|
||||
case IConfig::DnsIPv6Key: /* --ipv6 */
|
||||
return set(doc, DnsConfig::kField, DnsConfig::kIPv, 6);
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,9 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_ICONFIG_H
|
||||
#define XMRIG_ICONFIG_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "3rdparty/rapidjson/fwd.h"
|
||||
|
||||
@@ -82,7 +80,8 @@ public:
|
||||
HugePageSizeKey = 1050,
|
||||
PauseOnActiveKey = 1051,
|
||||
SubmitToOriginKey = 1052,
|
||||
DnsIPv6Key = 1053,
|
||||
DnsIPv4Key = '4',
|
||||
DnsIPv6Key = '6',
|
||||
DnsTtlKey = 1054,
|
||||
SpendSecretKey = 1055,
|
||||
DaemonZMQPortKey = 1056,
|
||||
@@ -177,7 +176,4 @@ public:
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif // XMRIG_ICONFIG_H
|
||||
} // namespace xmrig
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,21 +16,16 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_IDNSBACKEND_H
|
||||
#define XMRIG_IDNSBACKEND_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/tools/Object.h"
|
||||
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
class DnsConfig;
|
||||
class DnsRecords;
|
||||
class DnsRequest;
|
||||
class IDnsListener;
|
||||
class String;
|
||||
|
||||
@@ -43,12 +38,8 @@ public:
|
||||
IDnsBackend() = default;
|
||||
virtual ~IDnsBackend() = default;
|
||||
|
||||
virtual const DnsRecords &records() const = 0;
|
||||
virtual std::shared_ptr<DnsRequest> resolve(const String &host, IDnsListener *listener, uint64_t ttl) = 0;
|
||||
virtual void resolve(const String &host, const std::weak_ptr<IDnsListener> &listener, const DnsConfig &config) = 0;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif // XMRIG_IDNSBACKEND_H
|
||||
} // namespace xmrig
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
|
||||
#include "base/net/dns/Dns.h"
|
||||
#include "base/net/dns/DnsRequest.h"
|
||||
#include "base/net/dns/DnsUvBackend.h"
|
||||
|
||||
|
||||
@@ -25,17 +26,21 @@ namespace xmrig {
|
||||
|
||||
|
||||
DnsConfig Dns::m_config;
|
||||
std::map<String, std::shared_ptr<IDnsBackend> > Dns::m_backends;
|
||||
std::map<String, std::shared_ptr<IDnsBackend>> Dns::m_backends;
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
|
||||
|
||||
std::shared_ptr<xmrig::DnsRequest> xmrig::Dns::resolve(const String &host, IDnsListener *listener, uint64_t ttl)
|
||||
std::shared_ptr<xmrig::DnsRequest> xmrig::Dns::resolve(const String &host, IDnsListener *listener)
|
||||
{
|
||||
auto req = std::make_shared<DnsRequest>(listener);
|
||||
|
||||
if (m_backends.find(host) == m_backends.end()) {
|
||||
m_backends.insert({ host, std::make_shared<DnsUvBackend>() });
|
||||
}
|
||||
|
||||
return m_backends.at(host)->resolve(host, listener, ttl == 0 ? m_config.ttl() : ttl);
|
||||
m_backends.at(host)->resolve(host, req, m_config);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
inline static const DnsConfig &config() { return m_config; }
|
||||
inline static void set(const DnsConfig &config) { m_config = config; }
|
||||
|
||||
static std::shared_ptr<DnsRequest> resolve(const String &host, IDnsListener *listener, uint64_t ttl = 0);
|
||||
static std::shared_ptr<DnsRequest> resolve(const String &host, IDnsListener *listener);
|
||||
|
||||
private:
|
||||
static DnsConfig m_config;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -20,15 +20,15 @@
|
||||
#include "3rdparty/rapidjson/document.h"
|
||||
#include "base/io/json/Json.h"
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
const char *DnsConfig::kField = "dns";
|
||||
const char *DnsConfig::kIPv6 = "ipv6";
|
||||
const char *DnsConfig::kIPv = "ip_version";
|
||||
const char *DnsConfig::kTTL = "ttl";
|
||||
|
||||
|
||||
@@ -37,8 +37,26 @@ const char *DnsConfig::kTTL = "ttl";
|
||||
|
||||
xmrig::DnsConfig::DnsConfig(const rapidjson::Value &value)
|
||||
{
|
||||
m_ipv6 = Json::getBool(value, kIPv6, m_ipv6);
|
||||
m_ttl = std::max(Json::getUint(value, kTTL, m_ttl), 1U);
|
||||
const uint32_t ipv = Json::getUint(value, kIPv, m_ipv);
|
||||
if (ipv == 0 || ipv == 4 || ipv == 6) {
|
||||
m_ipv = ipv;
|
||||
}
|
||||
|
||||
m_ttl = std::max(Json::getUint(value, kTTL, m_ttl), 1U);
|
||||
}
|
||||
|
||||
|
||||
int xmrig::DnsConfig::ai_family() const
|
||||
{
|
||||
if (m_ipv == 4) {
|
||||
return AF_INET;
|
||||
}
|
||||
|
||||
if (m_ipv == 6) {
|
||||
return AF_INET6;
|
||||
}
|
||||
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +67,8 @@ rapidjson::Value xmrig::DnsConfig::toJSON(rapidjson::Document &doc) const
|
||||
auto &allocator = doc.GetAllocator();
|
||||
Value obj(kObjectType);
|
||||
|
||||
obj.AddMember(StringRef(kIPv6), m_ipv6, allocator);
|
||||
obj.AddMember(StringRef(kTTL), m_ttl, allocator);
|
||||
obj.AddMember(StringRef(kIPv), m_ipv, allocator);
|
||||
obj.AddMember(StringRef(kTTL), m_ttl, allocator);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,9 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_DNSCONFIG_H
|
||||
#define XMRIG_DNSCONFIG_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "3rdparty/rapidjson/fwd.h"
|
||||
|
||||
@@ -30,25 +28,22 @@ class DnsConfig
|
||||
{
|
||||
public:
|
||||
static const char *kField;
|
||||
static const char *kIPv6;
|
||||
static const char *kIPv;
|
||||
static const char *kTTL;
|
||||
|
||||
DnsConfig() = default;
|
||||
DnsConfig(const rapidjson::Value &value);
|
||||
|
||||
inline bool isIPv6() const { return m_ipv6; }
|
||||
inline uint32_t ipv() const { return m_ipv; }
|
||||
inline uint32_t ttl() const { return m_ttl * 1000U; }
|
||||
|
||||
int ai_family() const;
|
||||
rapidjson::Value toJSON(rapidjson::Document &doc) const;
|
||||
|
||||
|
||||
private:
|
||||
bool m_ipv6 = false;
|
||||
uint32_t m_ttl = 30U;
|
||||
uint32_t m_ttl = 30U;
|
||||
uint32_t m_ipv = 0U;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_DNSCONFIG_H */
|
||||
} // namespace xmrig
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2023 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2023 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,19 +16,16 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#include "base/net/dns/DnsRecord.h"
|
||||
|
||||
|
||||
xmrig::DnsRecord::DnsRecord(const addrinfo *addr) :
|
||||
m_type(addr->ai_family == AF_INET6 ? AAAA : (addr->ai_family == AF_INET ? A : Unknown))
|
||||
xmrig::DnsRecord::DnsRecord(const addrinfo *addr)
|
||||
{
|
||||
static_assert(sizeof(m_data) >= sizeof(sockaddr_in6), "Not enough storage for IPv6 address.");
|
||||
|
||||
memcpy(m_data, addr->ai_addr, m_type == AAAA ? sizeof(sockaddr_in6) : sizeof(sockaddr_in));
|
||||
memcpy(m_data, addr->ai_addr, addr->ai_family == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in));
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +41,7 @@ xmrig::String xmrig::DnsRecord::ip() const
|
||||
{
|
||||
char *buf = nullptr;
|
||||
|
||||
if (m_type == AAAA) {
|
||||
if (reinterpret_cast<const sockaddr &>(m_data).sa_family == AF_INET6) {
|
||||
buf = new char[45]();
|
||||
uv_ip6_name(reinterpret_cast<const sockaddr_in6*>(m_data), buf, 45);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,14 +16,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_DNSRECORD_H
|
||||
#define XMRIG_DNSRECORD_H
|
||||
|
||||
#pragma once
|
||||
|
||||
struct addrinfo;
|
||||
struct sockaddr;
|
||||
|
||||
|
||||
#include "base/tools/String.h"
|
||||
|
||||
|
||||
@@ -33,28 +30,15 @@ namespace xmrig {
|
||||
class DnsRecord
|
||||
{
|
||||
public:
|
||||
enum Type : uint32_t {
|
||||
Unknown,
|
||||
A,
|
||||
AAAA
|
||||
};
|
||||
|
||||
DnsRecord() {}
|
||||
DnsRecord(const addrinfo *addr);
|
||||
|
||||
const sockaddr *addr(uint16_t port = 0) const;
|
||||
String ip() const;
|
||||
|
||||
inline bool isValid() const { return m_type != Unknown; }
|
||||
inline Type type() const { return m_type; }
|
||||
|
||||
private:
|
||||
mutable uint8_t m_data[28]{};
|
||||
const Type m_type = Unknown;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_DNSRECORD_H */
|
||||
} // namespace xmrig
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -18,90 +18,96 @@
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#include "base/net/dns/DnsRecords.h"
|
||||
#include "base/net/dns/Dns.h"
|
||||
|
||||
|
||||
const xmrig::DnsRecord &xmrig::DnsRecords::get(DnsRecord::Type prefered) const
|
||||
namespace {
|
||||
|
||||
|
||||
static size_t dns_records_count(const addrinfo *res, int &ai_family)
|
||||
{
|
||||
size_t ipv4 = 0;
|
||||
size_t ipv6 = 0;
|
||||
|
||||
while (res != nullptr) {
|
||||
if (res->ai_family == AF_INET) {
|
||||
++ipv4;
|
||||
}
|
||||
|
||||
if (res->ai_family == AF_INET6) {
|
||||
++ipv6;
|
||||
}
|
||||
|
||||
res = res->ai_next;
|
||||
}
|
||||
|
||||
if (ai_family == AF_INET6 && !ipv6) {
|
||||
ai_family = AF_INET;
|
||||
}
|
||||
|
||||
switch (ai_family) {
|
||||
case AF_UNSPEC:
|
||||
return ipv4 + ipv6;
|
||||
|
||||
case AF_INET:
|
||||
return ipv4;
|
||||
|
||||
case AF_INET6:
|
||||
return ipv6;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
xmrig::DnsRecords::DnsRecords(const addrinfo *res, int ai_family)
|
||||
{
|
||||
size_t size = dns_records_count(res, ai_family);
|
||||
if (!size) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_records.reserve(size);
|
||||
|
||||
if (ai_family == AF_UNSPEC) {
|
||||
while (res != nullptr) {
|
||||
if (res->ai_family == AF_INET || res->ai_family == AF_INET6) {
|
||||
m_records.emplace_back(res);
|
||||
}
|
||||
|
||||
res = res->ai_next;
|
||||
};
|
||||
} else {
|
||||
while (res != nullptr) {
|
||||
if (res->ai_family == ai_family) {
|
||||
m_records.emplace_back(res);
|
||||
}
|
||||
|
||||
res = res->ai_next;
|
||||
};
|
||||
}
|
||||
|
||||
size = m_records.size();
|
||||
if (size > 1) {
|
||||
m_index = static_cast<size_t>(rand()) % size; // NOLINT(concurrency-mt-unsafe, cert-msc30-c, cert-msc50-cpp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const xmrig::DnsRecord &xmrig::DnsRecords::get() const
|
||||
{
|
||||
static const DnsRecord defaultRecord;
|
||||
|
||||
if (isEmpty()) {
|
||||
return defaultRecord;
|
||||
}
|
||||
|
||||
const size_t ipv4 = m_ipv4.size();
|
||||
const size_t ipv6 = m_ipv6.size();
|
||||
|
||||
if (ipv6 && (prefered == DnsRecord::AAAA || Dns::config().isIPv6() || !ipv4)) {
|
||||
return m_ipv6[ipv6 == 1 ? 0 : static_cast<size_t>(rand()) % ipv6]; // NOLINT(concurrency-mt-unsafe, cert-msc30-c, cert-msc50-cpp)
|
||||
}
|
||||
|
||||
if (ipv4) {
|
||||
return m_ipv4[ipv4 == 1 ? 0 : static_cast<size_t>(rand()) % ipv4]; // NOLINT(concurrency-mt-unsafe, cert-msc30-c, cert-msc50-cpp)
|
||||
const size_t size = m_records.size();
|
||||
if (size > 0) {
|
||||
return m_records[m_index++ % size];
|
||||
}
|
||||
|
||||
return defaultRecord;
|
||||
}
|
||||
|
||||
|
||||
size_t xmrig::DnsRecords::count(DnsRecord::Type type) const
|
||||
{
|
||||
if (type == DnsRecord::A) {
|
||||
return m_ipv4.size();
|
||||
}
|
||||
|
||||
if (type == DnsRecord::AAAA) {
|
||||
return m_ipv6.size();
|
||||
}
|
||||
|
||||
return m_ipv4.size() + m_ipv6.size();
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DnsRecords::clear()
|
||||
{
|
||||
m_ipv4.clear();
|
||||
m_ipv6.clear();
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DnsRecords::parse(addrinfo *res)
|
||||
{
|
||||
clear();
|
||||
|
||||
addrinfo *ptr = res;
|
||||
size_t ipv4 = 0;
|
||||
size_t ipv6 = 0;
|
||||
|
||||
while (ptr != nullptr) {
|
||||
if (ptr->ai_family == AF_INET) {
|
||||
++ipv4;
|
||||
}
|
||||
else if (ptr->ai_family == AF_INET6) {
|
||||
++ipv6;
|
||||
}
|
||||
|
||||
ptr = ptr->ai_next;
|
||||
}
|
||||
|
||||
if (ipv4 == 0 && ipv6 == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_ipv4.reserve(ipv4);
|
||||
m_ipv6.reserve(ipv6);
|
||||
|
||||
ptr = res;
|
||||
while (ptr != nullptr) {
|
||||
if (ptr->ai_family == AF_INET) {
|
||||
m_ipv4.emplace_back(ptr);
|
||||
}
|
||||
else if (ptr->ai_family == AF_INET6) {
|
||||
m_ipv6.emplace_back(ptr);
|
||||
}
|
||||
|
||||
ptr = ptr->ai_next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,9 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_DNSRECORDS_H
|
||||
#define XMRIG_DNSRECORDS_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/net/dns/DnsRecord.h"
|
||||
|
||||
@@ -29,20 +27,19 @@ namespace xmrig {
|
||||
class DnsRecords
|
||||
{
|
||||
public:
|
||||
inline bool isEmpty() const { return m_ipv4.empty() && m_ipv6.empty(); }
|
||||
DnsRecords() = default;
|
||||
DnsRecords(const addrinfo *res, int ai_family);
|
||||
|
||||
const DnsRecord &get(DnsRecord::Type prefered = DnsRecord::Unknown) const;
|
||||
size_t count(DnsRecord::Type type = DnsRecord::Unknown) const;
|
||||
void clear();
|
||||
void parse(addrinfo *res);
|
||||
inline bool isEmpty() const { return m_records.empty(); }
|
||||
inline const std::vector<DnsRecord> &records() const { return m_records; }
|
||||
inline size_t size() const { return m_records.size(); }
|
||||
|
||||
const DnsRecord &get() const;
|
||||
|
||||
private:
|
||||
std::vector<DnsRecord> m_ipv4;
|
||||
std::vector<DnsRecord> m_ipv6;
|
||||
mutable size_t m_index = 0;
|
||||
std::vector<DnsRecord> m_records;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_DNSRECORDS_H */
|
||||
} // namespace xmrig
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,35 +16,30 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_DNSREQUEST_H
|
||||
#define XMRIG_DNSREQUEST_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "base/tools/Object.h"
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include "base/kernel/interfaces/IDnsListener.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
class IDnsListener;
|
||||
|
||||
|
||||
class DnsRequest
|
||||
class DnsRequest : public IDnsListener
|
||||
{
|
||||
public:
|
||||
XMRIG_DISABLE_COPY_MOVE_DEFAULT(DnsRequest)
|
||||
|
||||
DnsRequest(IDnsListener *listener) : listener(listener) {}
|
||||
~DnsRequest() = default;
|
||||
inline DnsRequest(IDnsListener *listener) : m_listener(listener) {}
|
||||
~DnsRequest() override = default;
|
||||
|
||||
IDnsListener *listener;
|
||||
protected:
|
||||
inline void onResolved(const DnsRecords &records, int status, const char *error) override {
|
||||
m_listener->onResolved(records, status, error);
|
||||
}
|
||||
|
||||
private:
|
||||
IDnsListener *m_listener;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_DNSREQUEST_H */
|
||||
} // namespace xmrig
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2023 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2023 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,13 +16,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
|
||||
#include "base/net/dns/DnsUvBackend.h"
|
||||
#include "base/kernel/interfaces/IDnsListener.h"
|
||||
#include "base/net/dns/DnsRequest.h"
|
||||
#include "base/net/dns/DnsConfig.h"
|
||||
#include "base/tools/Chrono.h"
|
||||
|
||||
|
||||
@@ -73,21 +71,23 @@ xmrig::DnsUvBackend::~DnsUvBackend()
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<xmrig::DnsRequest> xmrig::DnsUvBackend::resolve(const String &host, IDnsListener *listener, uint64_t ttl)
|
||||
void xmrig::DnsUvBackend::resolve(const String &host, const std::weak_ptr<IDnsListener> &listener, const DnsConfig &config)
|
||||
{
|
||||
auto req = std::make_shared<DnsRequest>(listener);
|
||||
m_queue.emplace_back(listener);
|
||||
|
||||
if (Chrono::currentMSecsSinceEpoch() - m_ts <= ttl && !m_records.isEmpty()) {
|
||||
req->listener->onResolved(m_records, 0, nullptr);
|
||||
} else {
|
||||
m_queue.emplace(req);
|
||||
if (Chrono::currentMSecsSinceEpoch() - m_ts <= config.ttl()) {
|
||||
return notify();
|
||||
}
|
||||
|
||||
if (m_queue.size() == 1 && !resolve(host)) {
|
||||
done();
|
||||
if (m_req) {
|
||||
return;
|
||||
}
|
||||
|
||||
return req;
|
||||
m_ai_family = config.ai_family();
|
||||
|
||||
if (!resolve(host)) {
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,44 +102,46 @@ bool xmrig::DnsUvBackend::resolve(const String &host)
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DnsUvBackend::done()
|
||||
void xmrig::DnsUvBackend::notify()
|
||||
{
|
||||
const char *error = m_status < 0 ? uv_strerror(m_status) : nullptr;
|
||||
|
||||
while (!m_queue.empty()) {
|
||||
auto req = std::move(m_queue.front()).lock();
|
||||
if (req) {
|
||||
req->listener->onResolved(m_records, m_status, error);
|
||||
for (const auto &l : m_queue) {
|
||||
auto listener = l.lock();
|
||||
if (listener) {
|
||||
listener->onResolved(m_records, m_status, error);
|
||||
}
|
||||
|
||||
m_queue.pop();
|
||||
}
|
||||
|
||||
m_queue.clear();
|
||||
m_req.reset();
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DnsUvBackend::onResolved(int status, addrinfo *res)
|
||||
{
|
||||
m_ts = Chrono::currentMSecsSinceEpoch();
|
||||
m_status = status;
|
||||
m_ts = Chrono::currentMSecsSinceEpoch();
|
||||
|
||||
if ((m_status = status) < 0) {
|
||||
return done();
|
||||
if (m_status < 0) {
|
||||
m_records = {};
|
||||
|
||||
return notify();
|
||||
}
|
||||
|
||||
m_records.parse(res);
|
||||
m_records = { res, m_ai_family };
|
||||
|
||||
if (m_records.isEmpty()) {
|
||||
m_status = UV_EAI_NONAME;
|
||||
}
|
||||
|
||||
done();
|
||||
notify();
|
||||
}
|
||||
|
||||
|
||||
void xmrig::DnsUvBackend::onResolved(uv_getaddrinfo_t *req, int status, addrinfo *res)
|
||||
{
|
||||
auto backend = getStorage().get(req->data);
|
||||
auto *backend = getStorage().get(req->data);
|
||||
if (backend) {
|
||||
backend->onResolved(status, res);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,16 +16,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_DNSUVBACKEND_H
|
||||
#define XMRIG_DNSUVBACKEND_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/kernel/interfaces/IDnsBackend.h"
|
||||
#include "base/net/dns/DnsRecords.h"
|
||||
#include "base/net/tools/Storage.h"
|
||||
|
||||
|
||||
#include <queue>
|
||||
#include <deque>
|
||||
|
||||
|
||||
using uv_getaddrinfo_t = struct uv_getaddrinfo_s;
|
||||
@@ -43,20 +40,19 @@ public:
|
||||
~DnsUvBackend() override;
|
||||
|
||||
protected:
|
||||
inline const DnsRecords &records() const override { return m_records; }
|
||||
|
||||
std::shared_ptr<DnsRequest> resolve(const String &host, IDnsListener *listener, uint64_t ttl) override;
|
||||
void resolve(const String &host, const std::weak_ptr<IDnsListener> &listener, const DnsConfig &config) override;
|
||||
|
||||
private:
|
||||
bool resolve(const String &host);
|
||||
void done();
|
||||
void notify();
|
||||
void onResolved(int status, addrinfo *res);
|
||||
|
||||
static void onResolved(uv_getaddrinfo_t *req, int status, addrinfo *res);
|
||||
|
||||
DnsRecords m_records;
|
||||
int m_ai_family = 0;
|
||||
int m_status = 0;
|
||||
std::queue<std::weak_ptr<DnsRequest> > m_queue;
|
||||
std::deque<std::weak_ptr<IDnsListener>> m_queue;
|
||||
std::shared_ptr<uv_getaddrinfo_t> m_req;
|
||||
uint64_t m_ts = 0;
|
||||
uintptr_t m_key;
|
||||
@@ -66,7 +62,4 @@ private:
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
|
||||
#endif /* XMRIG_DNSUVBACKEND_H */
|
||||
} // namespace xmrig
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018 Lee Clagett <https://github.com/vtnerd>
|
||||
* Copyright (c) 2018-2023 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2023 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -45,7 +45,7 @@ namespace xmrig {
|
||||
|
||||
|
||||
// https://wiki.openssl.org/index.php/Diffie-Hellman_parameters
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L || (defined(LIBRESSL_VERSION_NUMBER) && !defined(LIBRESSL_HAS_TLS1_3))
|
||||
static DH *get_dh2048()
|
||||
{
|
||||
static unsigned char dhp_2048[] = {
|
||||
@@ -152,7 +152,7 @@ bool xmrig::TlsContext::load(const TlsConfig &config)
|
||||
SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
SSL_CTX_set_options(m_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
|
||||
# if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
# if OPENSSL_VERSION_NUMBER >= 0x1010100fL || defined(LIBRESSL_HAS_TLS1_3)
|
||||
SSL_CTX_set_max_early_data(m_ctx, 0);
|
||||
# endif
|
||||
|
||||
@@ -180,7 +180,7 @@ bool xmrig::TlsContext::setCipherSuites(const char *ciphersuites)
|
||||
return true;
|
||||
}
|
||||
|
||||
# if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
# if OPENSSL_VERSION_NUMBER >= 0x1010100fL || defined(LIBRESSL_HAS_TLS1_3)
|
||||
if (SSL_CTX_set_ciphersuites(m_ctx, ciphersuites) == 1) {
|
||||
return true;
|
||||
}
|
||||
@@ -194,7 +194,7 @@ bool xmrig::TlsContext::setCipherSuites(const char *ciphersuites)
|
||||
|
||||
bool xmrig::TlsContext::setDH(const char *dhparam)
|
||||
{
|
||||
# if OPENSSL_VERSION_NUMBER < 0x30000000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
# if OPENSSL_VERSION_NUMBER < 0x30000000L || (defined(LIBRESSL_VERSION_NUMBER) && !defined(LIBRESSL_HAS_TLS1_3))
|
||||
DH *dh = nullptr;
|
||||
|
||||
if (dhparam != nullptr) {
|
||||
|
||||
@@ -241,8 +241,13 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
ar(m_amount);
|
||||
ar(m_outputType);
|
||||
|
||||
// output type must be txout_to_key (2) or txout_to_tagged_key (3)
|
||||
if ((m_outputType != 2) && (m_outputType != 3)) {
|
||||
const bool is_fcmp_pp = (m_coin == Coin::MONERO) && (m_version.first >= 17);
|
||||
|
||||
// output type must be txout_to_key (2) or txout_to_tagged_key (3) for versions < 17, and txout_to_carrot_v1 (0) for version FCMP++
|
||||
if (is_fcmp_pp && (m_outputType == 0)) {
|
||||
// all good
|
||||
}
|
||||
else if ((m_outputType != 2) && (m_outputType != 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -250,6 +255,11 @@ bool xmrig::BlockTemplate::parse(bool hashes)
|
||||
|
||||
ar(m_ephPublicKey, kKeySize);
|
||||
|
||||
if (is_fcmp_pp) {
|
||||
ar(m_carrotViewTag);
|
||||
ar(m_janusAnchor);
|
||||
}
|
||||
|
||||
if (m_coin == Coin::ZEPHYR) {
|
||||
if (m_outputType != 2) {
|
||||
return false;
|
||||
|
||||
@@ -148,6 +148,8 @@ private:
|
||||
Buffer m_hashes;
|
||||
Buffer m_minerTxMerkleTreeBranch;
|
||||
uint8_t m_rootHash[kHashSize]{};
|
||||
uint8_t m_carrotViewTag[3]{};
|
||||
uint8_t m_janusAnchor[16]{};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
"dhparam": null
|
||||
},
|
||||
"dns": {
|
||||
"ipv6": false,
|
||||
"ip_version": 0,
|
||||
"ttl": 30
|
||||
},
|
||||
"user-agent": null,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -16,9 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_CONFIG_PLATFORM_H
|
||||
#define XMRIG_CONFIG_PLATFORM_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include "getopt/getopt.h"
|
||||
@@ -28,13 +26,12 @@
|
||||
|
||||
|
||||
#include "base/kernel/interfaces/IConfig.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
namespace xmrig {
|
||||
|
||||
|
||||
static const char short_options[] = "a:c:kBp:Px:r:R:s:t:T:o:u:O:v:l:Sx:";
|
||||
static const char short_options[] = "a:c:kBp:Px:r:R:s:t:T:o:u:O:v:l:Sx:46";
|
||||
|
||||
|
||||
static const option options[] = {
|
||||
@@ -99,7 +96,8 @@ static const option options[] = {
|
||||
{ "no-title", 0, nullptr, IConfig::NoTitleKey },
|
||||
{ "pause-on-battery", 0, nullptr, IConfig::PauseOnBatteryKey },
|
||||
{ "pause-on-active", 1, nullptr, IConfig::PauseOnActiveKey },
|
||||
{ "dns-ipv6", 0, nullptr, IConfig::DnsIPv6Key },
|
||||
{ "ipv4", 0, nullptr, IConfig::DnsIPv4Key },
|
||||
{ "ipv6", 0, nullptr, IConfig::DnsIPv6Key },
|
||||
{ "dns-ttl", 1, nullptr, IConfig::DnsTtlKey },
|
||||
{ "spend-secret-key", 1, nullptr, IConfig::SpendSecretKey },
|
||||
# ifdef XMRIG_FEATURE_BENCHMARK
|
||||
@@ -169,6 +167,3 @@ static const option options[] = {
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
|
||||
|
||||
#endif /* XMRIG_CONFIG_PLATFORM_H */
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* Copyright (c) 2014 Lucas Jones <https://github.com/lucasjones>
|
||||
* Copyright (c) 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
||||
* Copyright (c) 2016 Jay D Dee <jayddee246@gmail.com>
|
||||
* Copyright (c) 2018-2024 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2024 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -21,13 +21,10 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_USAGE_H
|
||||
#define XMRIG_USAGE_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "version.h"
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -59,7 +56,8 @@ static inline const std::string &usage()
|
||||
u += " --tls-fingerprint=HEX pool TLS certificate fingerprint for strict certificate pinning\n";
|
||||
# endif
|
||||
|
||||
u += " --dns-ipv6 prefer IPv6 records from DNS responses\n";
|
||||
u += " -4, --ipv4 resolve names to IPv4 addresses\n";
|
||||
u += " -6, --ipv6 resolve names to IPv6 addresses\n";
|
||||
u += " --dns-ttl=N N seconds (default: 30) TTL for internal DNS cache\n";
|
||||
|
||||
# ifdef XMRIG_FEATURE_HTTP
|
||||
@@ -205,6 +203,4 @@ static inline const std::string &usage()
|
||||
}
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
|
||||
#endif /* XMRIG_USAGE_H */
|
||||
} // namespace xmrig
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "crypto/common/VirtualMemory.h"
|
||||
|
||||
|
||||
#if defined(XMRIG_ARM)
|
||||
#if defined(XMRIG_ARM) || defined(XMRIG_RISCV)
|
||||
# include "crypto/cn/CryptoNight_arm.h"
|
||||
#else
|
||||
# include "crypto/cn/CryptoNight_x86.h"
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined _MSC_VER || defined XMRIG_ARM
|
||||
#if defined _MSC_VER || defined XMRIG_ARM || defined XMRIG_RISCV
|
||||
# define ABI_ATTRIBUTE
|
||||
#else
|
||||
# define ABI_ATTRIBUTE __attribute__((ms_abi))
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#ifndef XMRIG_CRYPTONIGHT_ARM_H
|
||||
#define XMRIG_CRYPTONIGHT_ARM_H
|
||||
|
||||
#ifdef XMRIG_RISCV
|
||||
# include "crypto/cn/sse2rvv.h"
|
||||
#endif
|
||||
|
||||
#include "base/crypto/keccak.h"
|
||||
#include "crypto/cn/CnAlgo.h"
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <math.h>
|
||||
|
||||
// VARIANT ALTERATIONS
|
||||
#ifndef XMRIG_ARM
|
||||
#if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
|
||||
# define VARIANT1_INIT(part) \
|
||||
uint64_t tweak1_2_##part = 0; \
|
||||
if (BASE == Algorithm::CN_1) { \
|
||||
@@ -60,7 +60,7 @@
|
||||
}
|
||||
|
||||
|
||||
#ifndef XMRIG_ARM
|
||||
#if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
|
||||
# define VARIANT2_INIT(part) \
|
||||
__m128i division_result_xmm_##part = _mm_cvtsi64_si128(static_cast<int64_t>(h##part[12])); \
|
||||
__m128i sqrt_result_xmm_##part = _mm_cvtsi64_si128(static_cast<int64_t>(h##part[13]));
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
#if defined(XMRIG_ARM)
|
||||
# include "crypto/cn/sse2neon.h"
|
||||
#elif defined(XMRIG_RISCV)
|
||||
# include "crypto/cn/sse2rvv.h"
|
||||
#elif defined(__GNUC__)
|
||||
# include <x86intrin.h>
|
||||
#else
|
||||
|
||||
748
src/crypto/cn/sse2rvv.h
Normal file
748
src/crypto/cn/sse2rvv.h
Normal file
@@ -0,0 +1,748 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2025 Slayingripper <https://github.com/Slayingripper>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SSE to RISC-V Vector (RVV) optimized compatibility header
|
||||
* Provides both scalar fallback and vectorized implementations using RVV intrinsics
|
||||
*
|
||||
* Based on sse2neon.h concepts, adapted for RISC-V architecture with RVV extensions
|
||||
* Original sse2neon.h: https://github.com/DLTcollab/sse2neon
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_SSE2RVV_OPTIMIZED_H
|
||||
#define XMRIG_SSE2RVV_OPTIMIZED_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Check if RVV is available */
|
||||
#if defined(__riscv_vector)
|
||||
#include <riscv_vector.h>
|
||||
#define USE_RVV_INTRINSICS 1
|
||||
#else
|
||||
#define USE_RVV_INTRINSICS 0
|
||||
#endif
|
||||
|
||||
/* 128-bit vector type */
|
||||
typedef union {
|
||||
uint8_t u8[16];
|
||||
uint16_t u16[8];
|
||||
uint32_t u32[4];
|
||||
uint64_t u64[2];
|
||||
int8_t i8[16];
|
||||
int16_t i16[8];
|
||||
int32_t i32[4];
|
||||
int64_t i64[2];
|
||||
} __m128i_union;
|
||||
|
||||
typedef __m128i_union __m128i;
|
||||
|
||||
/* Set operations */
|
||||
static inline __m128i _mm_set_epi32(int e3, int e2, int e1, int e0)
|
||||
{
|
||||
__m128i result;
|
||||
result.i32[0] = e0;
|
||||
result.i32[1] = e1;
|
||||
result.i32[2] = e2;
|
||||
result.i32[3] = e3;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_set_epi64x(int64_t e1, int64_t e0)
|
||||
{
|
||||
__m128i result;
|
||||
result.i64[0] = e0;
|
||||
result.i64[1] = e1;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_setzero_si128(void)
|
||||
{
|
||||
__m128i result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Extract/insert operations */
|
||||
static inline int _mm_cvtsi128_si32(__m128i a)
|
||||
{
|
||||
return a.i32[0];
|
||||
}
|
||||
|
||||
static inline int64_t _mm_cvtsi128_si64(__m128i a)
|
||||
{
|
||||
return a.i64[0];
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cvtsi32_si128(int a)
|
||||
{
|
||||
__m128i result = _mm_setzero_si128();
|
||||
result.i32[0] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cvtsi64_si128(int64_t a)
|
||||
{
|
||||
__m128i result = _mm_setzero_si128();
|
||||
result.i64[0] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Shuffle operations */
|
||||
static inline __m128i _mm_shuffle_epi32(__m128i a, int imm8)
|
||||
{
|
||||
__m128i result;
|
||||
result.u32[0] = a.u32[(imm8 >> 0) & 0x3];
|
||||
result.u32[1] = a.u32[(imm8 >> 2) & 0x3];
|
||||
result.u32[2] = a.u32[(imm8 >> 4) & 0x3];
|
||||
result.u32[3] = a.u32[(imm8 >> 6) & 0x3];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Logical operations - optimized with RVV when available */
|
||||
static inline __m128i _mm_xor_si128(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vxor_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] ^ b.u64[0];
|
||||
result.u64[1] = a.u64[1] ^ b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_or_si128(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vor_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] | b.u64[0];
|
||||
result.u64[1] = a.u64[1] | b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_and_si128(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vand_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] & b.u64[0];
|
||||
result.u64[1] = a.u64[1] & b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_andnot_si128(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vnot_a = __riscv_vnot_v_u64m1(va, vl);
|
||||
vuint64m1_t vr = __riscv_vand_vv_u64m1(vnot_a, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = (~a.u64[0]) & b.u64[0];
|
||||
result.u64[1] = (~a.u64[1]) & b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Shift operations */
|
||||
static inline __m128i _mm_slli_si128(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
size_t vl = __riscv_vsetvl_e8m1(16);
|
||||
vuint8m1_t va = __riscv_vle8_v_u8m1(a.u8, vl);
|
||||
vuint8m1_t vr = __riscv_vslideup_vx_u8m1(__riscv_vmv_v_x_u8m1(0, vl), va, count, vl);
|
||||
__riscv_vse8_v_u8m1(result.u8, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
for (int i = 0; i < 16 - count; i++) {
|
||||
result.u8[i + count] = a.u8[i];
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_srli_si128(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
size_t vl = __riscv_vsetvl_e8m1(16);
|
||||
vuint8m1_t va = __riscv_vle8_v_u8m1(a.u8, vl);
|
||||
vuint8m1_t vr = __riscv_vslidedown_vx_u8m1(va, count, vl);
|
||||
__riscv_vse8_v_u8m1(result.u8, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
for (int i = count; i < 16; i++) {
|
||||
result.u8[i - count] = a.u8[i];
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_slli_epi64(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vsll_vx_u64m1(va, imm8, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
result.u64[0] = a.u64[0] << imm8;
|
||||
result.u64[1] = a.u64[1] << imm8;
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_srli_epi64(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vsrl_vx_u64m1(va, imm8, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
result.u64[0] = a.u64[0] >> imm8;
|
||||
result.u64[1] = a.u64[1] >> imm8;
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Load/store operations - optimized with RVV */
|
||||
static inline __m128i _mm_load_si128(const __m128i* p)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t v = __riscv_vle64_v_u64m1((const uint64_t*)p, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, v, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
memcpy(&result, p, sizeof(__m128i));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_loadu_si128(const __m128i* p)
|
||||
{
|
||||
__m128i result;
|
||||
memcpy(&result, p, sizeof(__m128i));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void _mm_store_si128(__m128i* p, __m128i a)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t v = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
__riscv_vse64_v_u64m1((uint64_t*)p, v, vl);
|
||||
#else
|
||||
memcpy(p, &a, sizeof(__m128i));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void _mm_storeu_si128(__m128i* p, __m128i a)
|
||||
{
|
||||
memcpy(p, &a, sizeof(__m128i));
|
||||
}
|
||||
|
||||
/* Arithmetic operations - optimized with RVV */
|
||||
static inline __m128i _mm_add_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vadd_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] + b.u64[0];
|
||||
result.u64[1] = a.u64[1] + b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_add_epi32(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e32m1(4);
|
||||
vuint32m1_t va = __riscv_vle32_v_u32m1(a.u32, vl);
|
||||
vuint32m1_t vb = __riscv_vle32_v_u32m1(b.u32, vl);
|
||||
vuint32m1_t vr = __riscv_vadd_vv_u32m1(va, vb, vl);
|
||||
__riscv_vse32_v_u32m1(result.u32, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.i32[i] = a.i32[i] + b.i32[i];
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_sub_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vsub_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] - b.u64[0];
|
||||
result.u64[1] = a.u64[1] - b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_mul_epu32(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va_lo = __riscv_vzext_vf2_u64m1(__riscv_vle32_v_u32mf2(&a.u32[0], 2), vl);
|
||||
vuint64m1_t vb_lo = __riscv_vzext_vf2_u64m1(__riscv_vle32_v_u32mf2(&b.u32[0], 2), vl);
|
||||
vuint64m1_t vr = __riscv_vmul_vv_u64m1(va_lo, vb_lo, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = (uint64_t)a.u32[0] * (uint64_t)b.u32[0];
|
||||
result.u64[1] = (uint64_t)a.u32[2] * (uint64_t)b.u32[2];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Unpack operations */
|
||||
static inline __m128i _mm_unpacklo_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0];
|
||||
result.u64[1] = b.u64[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_unpackhi_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[1];
|
||||
result.u64[1] = b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Pause instruction for spin-wait loops */
|
||||
static inline void _mm_pause(void)
|
||||
{
|
||||
/* RISC-V pause hint if available (requires Zihintpause extension) */
|
||||
#if defined(__riscv_zihintpause)
|
||||
__asm__ __volatile__("pause");
|
||||
#else
|
||||
__asm__ __volatile__("nop");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Memory fence - optimized for RISC-V */
|
||||
static inline void _mm_mfence(void)
|
||||
{
|
||||
__asm__ __volatile__("fence rw,rw" ::: "memory");
|
||||
}
|
||||
|
||||
static inline void _mm_lfence(void)
|
||||
{
|
||||
__asm__ __volatile__("fence r,r" ::: "memory");
|
||||
}
|
||||
|
||||
static inline void _mm_sfence(void)
|
||||
{
|
||||
__asm__ __volatile__("fence w,w" ::: "memory");
|
||||
}
|
||||
|
||||
/* Comparison operations */
|
||||
static inline __m128i _mm_cmpeq_epi32(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = (a.u32[i] == b.u32[i]) ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cmpeq_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
result.u64[i] = (a.u64[i] == b.u64[i]) ? 0xFFFFFFFFFFFFFFFFULL : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Additional shift operations */
|
||||
static inline __m128i _mm_slli_epi32(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
memset(&result, 0, sizeof(result));
|
||||
} else {
|
||||
size_t vl = __riscv_vsetvl_e32m1(4);
|
||||
vuint32m1_t va = __riscv_vle32_v_u32m1(a.u32, vl);
|
||||
vuint32m1_t vr = __riscv_vsll_vx_u32m1(va, imm8, vl);
|
||||
__riscv_vse32_v_u32m1(result.u32, vr, vl);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
for (int i = 0; i < 4; i++) result.u32[i] = 0;
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = a.u32[i] << imm8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_srli_epi32(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
memset(&result, 0, sizeof(result));
|
||||
} else {
|
||||
size_t vl = __riscv_vsetvl_e32m1(4);
|
||||
vuint32m1_t va = __riscv_vle32_v_u32m1(a.u32, vl);
|
||||
vuint32m1_t vr = __riscv_vsrl_vx_u32m1(va, imm8, vl);
|
||||
__riscv_vse32_v_u32m1(result.u32, vr, vl);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
for (int i = 0; i < 4; i++) result.u32[i] = 0;
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = a.u32[i] >> imm8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 64-bit integer operations */
|
||||
static inline __m128i _mm_set1_epi64x(int64_t a)
|
||||
{
|
||||
__m128i result;
|
||||
result.i64[0] = a;
|
||||
result.i64[1] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Float type for compatibility */
|
||||
typedef __m128i __m128;
|
||||
|
||||
/* Float operations - simplified scalar implementations */
|
||||
static inline __m128 _mm_set1_ps(float a)
|
||||
{
|
||||
__m128 result;
|
||||
uint32_t val;
|
||||
memcpy(&val, &a, sizeof(float));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = val;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_setzero_ps(void)
|
||||
{
|
||||
__m128 result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_add_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
float fa[4], fb[4], fr[4];
|
||||
memcpy(fa, &a, sizeof(__m128));
|
||||
memcpy(fb, &b, sizeof(__m128));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fr[i] = fa[i] + fb[i];
|
||||
}
|
||||
memcpy(&result, fr, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_mul_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
float fa[4], fb[4], fr[4];
|
||||
memcpy(fa, &a, sizeof(__m128));
|
||||
memcpy(fb, &b, sizeof(__m128));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fr[i] = fa[i] * fb[i];
|
||||
}
|
||||
memcpy(&result, fr, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_and_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
result.u64[0] = a.u64[0] & b.u64[0];
|
||||
result.u64[1] = a.u64[1] & b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_or_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
result.u64[0] = a.u64[0] | b.u64[0];
|
||||
result.u64[1] = a.u64[1] | b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_cvtepi32_ps(__m128i a)
|
||||
{
|
||||
__m128 result;
|
||||
float fr[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fr[i] = (float)a.i32[i];
|
||||
}
|
||||
memcpy(&result, fr, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cvttps_epi32(__m128 a)
|
||||
{
|
||||
__m128i result;
|
||||
float fa[4];
|
||||
memcpy(fa, &a, sizeof(__m128));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.i32[i] = (int32_t)fa[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Casting operations */
|
||||
static inline __m128 _mm_castsi128_ps(__m128i a)
|
||||
{
|
||||
__m128 result;
|
||||
memcpy(&result, &a, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_castps_si128(__m128 a)
|
||||
{
|
||||
__m128i result;
|
||||
memcpy(&result, &a, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Additional set operations */
|
||||
static inline __m128i _mm_set1_epi32(int a)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.i32[i] = a;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* AES instructions - placeholders for soft_aes compatibility */
|
||||
static inline __m128i _mm_aesenc_si128(__m128i a, __m128i roundkey)
|
||||
{
|
||||
return _mm_xor_si128(a, roundkey);
|
||||
}
|
||||
|
||||
static inline __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
/* Rotate right operation for soft_aes.h */
|
||||
static inline uint32_t _rotr(uint32_t value, unsigned int count)
|
||||
{
|
||||
const unsigned int mask = 31;
|
||||
count &= mask;
|
||||
return (value >> count) | (value << ((-count) & mask));
|
||||
}
|
||||
|
||||
/* ARM NEON compatibility types and intrinsics for RISC-V */
|
||||
typedef __m128i_union uint64x2_t;
|
||||
typedef __m128i_union uint8x16_t;
|
||||
typedef __m128i_union int64x2_t;
|
||||
typedef __m128i_union int32x4_t;
|
||||
|
||||
static inline uint64x2_t vld1q_u64(const uint64_t *ptr)
|
||||
{
|
||||
uint64x2_t result;
|
||||
result.u64[0] = ptr[0];
|
||||
result.u64[1] = ptr[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int64x2_t vld1q_s64(const int64_t *ptr)
|
||||
{
|
||||
int64x2_t result;
|
||||
result.i64[0] = ptr[0];
|
||||
result.i64[1] = ptr[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void vst1q_u64(uint64_t *ptr, uint64x2_t val)
|
||||
{
|
||||
ptr[0] = val.u64[0];
|
||||
ptr[1] = val.u64[1];
|
||||
}
|
||||
|
||||
static inline uint64x2_t veorq_u64(uint64x2_t a, uint64x2_t b)
|
||||
{
|
||||
return _mm_xor_si128(a, b);
|
||||
}
|
||||
|
||||
static inline uint64x2_t vaddq_u64(uint64x2_t a, uint64x2_t b)
|
||||
{
|
||||
return _mm_add_epi64(a, b);
|
||||
}
|
||||
|
||||
static inline uint64x2_t vreinterpretq_u64_u8(uint8x16_t a)
|
||||
{
|
||||
uint64x2_t result;
|
||||
memcpy(&result, &a, sizeof(uint64x2_t));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64_t vgetq_lane_u64(uint64x2_t v, int lane)
|
||||
{
|
||||
return v.u64[lane];
|
||||
}
|
||||
|
||||
static inline int64_t vgetq_lane_s64(int64x2_t v, int lane)
|
||||
{
|
||||
return v.i64[lane];
|
||||
}
|
||||
|
||||
static inline int32_t vgetq_lane_s32(int32x4_t v, int lane)
|
||||
{
|
||||
return v.i32[lane];
|
||||
}
|
||||
|
||||
typedef struct { uint64_t val[1]; } uint64x1_t;
|
||||
|
||||
static inline uint64x1_t vcreate_u64(uint64_t a)
|
||||
{
|
||||
uint64x1_t result;
|
||||
result.val[0] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64x2_t vcombine_u64(uint64x1_t low, uint64x1_t high)
|
||||
{
|
||||
uint64x2_t result;
|
||||
result.u64[0] = low.val[0];
|
||||
result.u64[1] = high.val[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XMRIG_SSE2RVV_OPTIMIZED_H */
|
||||
748
src/crypto/cn/sse2rvv_optimized.h
Normal file
748
src/crypto/cn/sse2rvv_optimized.h
Normal file
@@ -0,0 +1,748 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2025 XMRig <https://github.com/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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SSE to RISC-V Vector (RVV) optimized compatibility header
|
||||
* Provides both scalar fallback and vectorized implementations using RVV intrinsics
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_SSE2RVV_OPTIMIZED_H
|
||||
#define XMRIG_SSE2RVV_OPTIMIZED_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Check if RVV is available */
|
||||
#if defined(__riscv_vector)
|
||||
#include <riscv_vector.h>
|
||||
#define USE_RVV_INTRINSICS 1
|
||||
#else
|
||||
#define USE_RVV_INTRINSICS 0
|
||||
#endif
|
||||
|
||||
/* 128-bit vector type */
|
||||
typedef union {
|
||||
uint8_t u8[16];
|
||||
uint16_t u16[8];
|
||||
uint32_t u32[4];
|
||||
uint64_t u64[2];
|
||||
int8_t i8[16];
|
||||
int16_t i16[8];
|
||||
int32_t i32[4];
|
||||
int64_t i64[2];
|
||||
#if USE_RVV_INTRINSICS
|
||||
vuint64m1_t rvv_u64;
|
||||
vuint32m1_t rvv_u32;
|
||||
vuint8m1_t rvv_u8;
|
||||
#endif
|
||||
} __m128i_union;
|
||||
|
||||
typedef __m128i_union __m128i;
|
||||
|
||||
/* Set operations */
|
||||
static inline __m128i _mm_set_epi32(int e3, int e2, int e1, int e0)
|
||||
{
|
||||
__m128i result;
|
||||
result.i32[0] = e0;
|
||||
result.i32[1] = e1;
|
||||
result.i32[2] = e2;
|
||||
result.i32[3] = e3;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_set_epi64x(int64_t e1, int64_t e0)
|
||||
{
|
||||
__m128i result;
|
||||
result.i64[0] = e0;
|
||||
result.i64[1] = e1;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_setzero_si128(void)
|
||||
{
|
||||
__m128i result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Extract/insert operations */
|
||||
static inline int _mm_cvtsi128_si32(__m128i a)
|
||||
{
|
||||
return a.i32[0];
|
||||
}
|
||||
|
||||
static inline int64_t _mm_cvtsi128_si64(__m128i a)
|
||||
{
|
||||
return a.i64[0];
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cvtsi32_si128(int a)
|
||||
{
|
||||
__m128i result = _mm_setzero_si128();
|
||||
result.i32[0] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cvtsi64_si128(int64_t a)
|
||||
{
|
||||
__m128i result = _mm_setzero_si128();
|
||||
result.i64[0] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Shuffle operations */
|
||||
static inline __m128i _mm_shuffle_epi32(__m128i a, int imm8)
|
||||
{
|
||||
__m128i result;
|
||||
result.u32[0] = a.u32[(imm8 >> 0) & 0x3];
|
||||
result.u32[1] = a.u32[(imm8 >> 2) & 0x3];
|
||||
result.u32[2] = a.u32[(imm8 >> 4) & 0x3];
|
||||
result.u32[3] = a.u32[(imm8 >> 6) & 0x3];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Logical operations - optimized with RVV when available */
|
||||
static inline __m128i _mm_xor_si128(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vxor_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] ^ b.u64[0];
|
||||
result.u64[1] = a.u64[1] ^ b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_or_si128(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vor_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] | b.u64[0];
|
||||
result.u64[1] = a.u64[1] | b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_and_si128(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vand_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] & b.u64[0];
|
||||
result.u64[1] = a.u64[1] & b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_andnot_si128(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vnot_a = __riscv_vnot_v_u64m1(va, vl);
|
||||
vuint64m1_t vr = __riscv_vand_vv_u64m1(vnot_a, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = (~a.u64[0]) & b.u64[0];
|
||||
result.u64[1] = (~a.u64[1]) & b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Shift operations */
|
||||
static inline __m128i _mm_slli_si128(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
size_t vl = __riscv_vsetvl_e8m1(16);
|
||||
vuint8m1_t va = __riscv_vle8_v_u8m1(a.u8, vl);
|
||||
vuint8m1_t vr = __riscv_vslideup_vx_u8m1(__riscv_vmv_v_x_u8m1(0, vl), va, count, vl);
|
||||
__riscv_vse8_v_u8m1(result.u8, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
for (int i = 0; i < 16 - count; i++) {
|
||||
result.u8[i + count] = a.u8[i];
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_srli_si128(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
size_t vl = __riscv_vsetvl_e8m1(16);
|
||||
vuint8m1_t va = __riscv_vle8_v_u8m1(a.u8, vl);
|
||||
vuint8m1_t vr = __riscv_vslidedown_vx_u8m1(va, count, vl);
|
||||
__riscv_vse8_v_u8m1(result.u8, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
for (int i = count; i < 16; i++) {
|
||||
result.u8[i - count] = a.u8[i];
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_slli_epi64(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vsll_vx_u64m1(va, imm8, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
result.u64[0] = a.u64[0] << imm8;
|
||||
result.u64[1] = a.u64[1] << imm8;
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_srli_epi64(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vsrl_vx_u64m1(va, imm8, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
result.u64[0] = a.u64[0] >> imm8;
|
||||
result.u64[1] = a.u64[1] >> imm8;
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Load/store operations - optimized with RVV */
|
||||
static inline __m128i _mm_load_si128(const __m128i* p)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t v = __riscv_vle64_v_u64m1((const uint64_t*)p, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, v, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
memcpy(&result, p, sizeof(__m128i));
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_loadu_si128(const __m128i* p)
|
||||
{
|
||||
__m128i result;
|
||||
memcpy(&result, p, sizeof(__m128i));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void _mm_store_si128(__m128i* p, __m128i a)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t v = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
__riscv_vse64_v_u64m1((uint64_t*)p, v, vl);
|
||||
#else
|
||||
memcpy(p, &a, sizeof(__m128i));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void _mm_storeu_si128(__m128i* p, __m128i a)
|
||||
{
|
||||
memcpy(p, &a, sizeof(__m128i));
|
||||
}
|
||||
|
||||
/* Arithmetic operations - optimized with RVV */
|
||||
static inline __m128i _mm_add_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vadd_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] + b.u64[0];
|
||||
result.u64[1] = a.u64[1] + b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_add_epi32(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e32m1(4);
|
||||
vuint32m1_t va = __riscv_vle32_v_u32m1(a.u32, vl);
|
||||
vuint32m1_t vb = __riscv_vle32_v_u32m1(b.u32, vl);
|
||||
vuint32m1_t vr = __riscv_vadd_vv_u32m1(va, vb, vl);
|
||||
__riscv_vse32_v_u32m1(result.u32, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.i32[i] = a.i32[i] + b.i32[i];
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_sub_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va = __riscv_vle64_v_u64m1(a.u64, vl);
|
||||
vuint64m1_t vb = __riscv_vle64_v_u64m1(b.u64, vl);
|
||||
vuint64m1_t vr = __riscv_vsub_vv_u64m1(va, vb, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] - b.u64[0];
|
||||
result.u64[1] = a.u64[1] - b.u64[1];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_mul_epu32(__m128i a, __m128i b)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
size_t vl = __riscv_vsetvl_e64m1(2);
|
||||
vuint64m1_t va_lo = __riscv_vzext_vf2_u64m1(__riscv_vle32_v_u32mf2(&a.u32[0], 2), vl);
|
||||
vuint64m1_t vb_lo = __riscv_vzext_vf2_u64m1(__riscv_vle32_v_u32mf2(&b.u32[0], 2), vl);
|
||||
vuint64m1_t vr = __riscv_vmul_vv_u64m1(va_lo, vb_lo, vl);
|
||||
__riscv_vse64_v_u64m1(result.u64, vr, vl);
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
result.u64[0] = (uint64_t)a.u32[0] * (uint64_t)b.u32[0];
|
||||
result.u64[1] = (uint64_t)a.u32[2] * (uint64_t)b.u32[2];
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Unpack operations */
|
||||
static inline __m128i _mm_unpacklo_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0];
|
||||
result.u64[1] = b.u64[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_unpackhi_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[1];
|
||||
result.u64[1] = b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Pause instruction for spin-wait loops */
|
||||
static inline void _mm_pause(void)
|
||||
{
|
||||
/* RISC-V pause hint if available (requires Zihintpause extension) */
|
||||
#if defined(__riscv_zihintpause)
|
||||
__asm__ __volatile__("pause");
|
||||
#else
|
||||
__asm__ __volatile__("nop");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Memory fence - optimized for RISC-V */
|
||||
static inline void _mm_mfence(void)
|
||||
{
|
||||
__asm__ __volatile__("fence rw,rw" ::: "memory");
|
||||
}
|
||||
|
||||
static inline void _mm_lfence(void)
|
||||
{
|
||||
__asm__ __volatile__("fence r,r" ::: "memory");
|
||||
}
|
||||
|
||||
static inline void _mm_sfence(void)
|
||||
{
|
||||
__asm__ __volatile__("fence w,w" ::: "memory");
|
||||
}
|
||||
|
||||
/* Comparison operations */
|
||||
static inline __m128i _mm_cmpeq_epi32(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = (a.u32[i] == b.u32[i]) ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cmpeq_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
result.u64[i] = (a.u64[i] == b.u64[i]) ? 0xFFFFFFFFFFFFFFFFULL : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Additional shift operations */
|
||||
static inline __m128i _mm_slli_epi32(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
memset(&result, 0, sizeof(result));
|
||||
} else {
|
||||
size_t vl = __riscv_vsetvl_e32m1(4);
|
||||
vuint32m1_t va = __riscv_vle32_v_u32m1(a.u32, vl);
|
||||
vuint32m1_t vr = __riscv_vsll_vx_u32m1(va, imm8, vl);
|
||||
__riscv_vse32_v_u32m1(result.u32, vr, vl);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
for (int i = 0; i < 4; i++) result.u32[i] = 0;
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = a.u32[i] << imm8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i _mm_srli_epi32(__m128i a, int imm8)
|
||||
{
|
||||
#if USE_RVV_INTRINSICS
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
memset(&result, 0, sizeof(result));
|
||||
} else {
|
||||
size_t vl = __riscv_vsetvl_e32m1(4);
|
||||
vuint32m1_t va = __riscv_vle32_v_u32m1(a.u32, vl);
|
||||
vuint32m1_t vr = __riscv_vsrl_vx_u32m1(va, imm8, vl);
|
||||
__riscv_vse32_v_u32m1(result.u32, vr, vl);
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
for (int i = 0; i < 4; i++) result.u32[i] = 0;
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = a.u32[i] >> imm8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 64-bit integer operations */
|
||||
static inline __m128i _mm_set1_epi64x(int64_t a)
|
||||
{
|
||||
__m128i result;
|
||||
result.i64[0] = a;
|
||||
result.i64[1] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Float type for compatibility */
|
||||
typedef __m128i __m128;
|
||||
|
||||
/* Float operations - simplified scalar implementations */
|
||||
static inline __m128 _mm_set1_ps(float a)
|
||||
{
|
||||
__m128 result;
|
||||
uint32_t val;
|
||||
memcpy(&val, &a, sizeof(float));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = val;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_setzero_ps(void)
|
||||
{
|
||||
__m128 result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_add_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
float fa[4], fb[4], fr[4];
|
||||
memcpy(fa, &a, sizeof(__m128));
|
||||
memcpy(fb, &b, sizeof(__m128));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fr[i] = fa[i] + fb[i];
|
||||
}
|
||||
memcpy(&result, fr, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_mul_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
float fa[4], fb[4], fr[4];
|
||||
memcpy(fa, &a, sizeof(__m128));
|
||||
memcpy(fb, &b, sizeof(__m128));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fr[i] = fa[i] * fb[i];
|
||||
}
|
||||
memcpy(&result, fr, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_and_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
result.u64[0] = a.u64[0] & b.u64[0];
|
||||
result.u64[1] = a.u64[1] & b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_or_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
result.u64[0] = a.u64[0] | b.u64[0];
|
||||
result.u64[1] = a.u64[1] | b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_cvtepi32_ps(__m128i a)
|
||||
{
|
||||
__m128 result;
|
||||
float fr[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fr[i] = (float)a.i32[i];
|
||||
}
|
||||
memcpy(&result, fr, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cvttps_epi32(__m128 a)
|
||||
{
|
||||
__m128i result;
|
||||
float fa[4];
|
||||
memcpy(fa, &a, sizeof(__m128));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.i32[i] = (int32_t)fa[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Casting operations */
|
||||
static inline __m128 _mm_castsi128_ps(__m128i a)
|
||||
{
|
||||
__m128 result;
|
||||
memcpy(&result, &a, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_castps_si128(__m128 a)
|
||||
{
|
||||
__m128i result;
|
||||
memcpy(&result, &a, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Additional set operations */
|
||||
static inline __m128i _mm_set1_epi32(int a)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.i32[i] = a;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* AES instructions - placeholders for soft_aes compatibility */
|
||||
static inline __m128i _mm_aesenc_si128(__m128i a, __m128i roundkey)
|
||||
{
|
||||
return _mm_xor_si128(a, roundkey);
|
||||
}
|
||||
|
||||
static inline __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
/* Rotate right operation for soft_aes.h */
|
||||
static inline uint32_t _rotr(uint32_t value, unsigned int count)
|
||||
{
|
||||
const unsigned int mask = 31;
|
||||
count &= mask;
|
||||
return (value >> count) | (value << ((-count) & mask));
|
||||
}
|
||||
|
||||
/* ARM NEON compatibility types and intrinsics for RISC-V */
|
||||
typedef __m128i_union uint64x2_t;
|
||||
typedef __m128i_union uint8x16_t;
|
||||
typedef __m128i_union int64x2_t;
|
||||
typedef __m128i_union int32x4_t;
|
||||
|
||||
static inline uint64x2_t vld1q_u64(const uint64_t *ptr)
|
||||
{
|
||||
uint64x2_t result;
|
||||
result.u64[0] = ptr[0];
|
||||
result.u64[1] = ptr[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int64x2_t vld1q_s64(const int64_t *ptr)
|
||||
{
|
||||
int64x2_t result;
|
||||
result.i64[0] = ptr[0];
|
||||
result.i64[1] = ptr[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void vst1q_u64(uint64_t *ptr, uint64x2_t val)
|
||||
{
|
||||
ptr[0] = val.u64[0];
|
||||
ptr[1] = val.u64[1];
|
||||
}
|
||||
|
||||
static inline uint64x2_t veorq_u64(uint64x2_t a, uint64x2_t b)
|
||||
{
|
||||
return _mm_xor_si128(a, b);
|
||||
}
|
||||
|
||||
static inline uint64x2_t vaddq_u64(uint64x2_t a, uint64x2_t b)
|
||||
{
|
||||
return _mm_add_epi64(a, b);
|
||||
}
|
||||
|
||||
static inline uint64x2_t vreinterpretq_u64_u8(uint8x16_t a)
|
||||
{
|
||||
uint64x2_t result;
|
||||
memcpy(&result, &a, sizeof(uint64x2_t));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64_t vgetq_lane_u64(uint64x2_t v, int lane)
|
||||
{
|
||||
return v.u64[lane];
|
||||
}
|
||||
|
||||
static inline int64_t vgetq_lane_s64(int64x2_t v, int lane)
|
||||
{
|
||||
return v.i64[lane];
|
||||
}
|
||||
|
||||
static inline int32_t vgetq_lane_s32(int32x4_t v, int lane)
|
||||
{
|
||||
return v.i32[lane];
|
||||
}
|
||||
|
||||
typedef struct { uint64_t val[1]; } uint64x1_t;
|
||||
|
||||
static inline uint64x1_t vcreate_u64(uint64_t a)
|
||||
{
|
||||
uint64x1_t result;
|
||||
result.val[0] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64x2_t vcombine_u64(uint64x1_t low, uint64x1_t high)
|
||||
{
|
||||
uint64x2_t result;
|
||||
result.u64[0] = low.val[0];
|
||||
result.u64[1] = high.val[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XMRIG_SSE2RVV_OPTIMIZED_H */
|
||||
571
src/crypto/cn/sse2rvv_scalar_backup.h
Normal file
571
src/crypto/cn/sse2rvv_scalar_backup.h
Normal file
@@ -0,0 +1,571 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2025 XMRig <https://github.com/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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SSE to RISC-V compatibility header
|
||||
* Provides scalar implementations of SSE intrinsics for RISC-V architecture
|
||||
*/
|
||||
|
||||
#ifndef XMRIG_SSE2RVV_H
|
||||
#define XMRIG_SSE2RVV_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/* 128-bit vector type */
|
||||
typedef union {
|
||||
uint8_t u8[16];
|
||||
uint16_t u16[8];
|
||||
uint32_t u32[4];
|
||||
uint64_t u64[2];
|
||||
int8_t i8[16];
|
||||
int16_t i16[8];
|
||||
int32_t i32[4];
|
||||
int64_t i64[2];
|
||||
} __m128i_union;
|
||||
|
||||
typedef __m128i_union __m128i;
|
||||
|
||||
/* Set operations */
|
||||
static inline __m128i _mm_set_epi32(int e3, int e2, int e1, int e0)
|
||||
{
|
||||
__m128i result;
|
||||
result.i32[0] = e0;
|
||||
result.i32[1] = e1;
|
||||
result.i32[2] = e2;
|
||||
result.i32[3] = e3;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_set_epi64x(int64_t e1, int64_t e0)
|
||||
{
|
||||
__m128i result;
|
||||
result.i64[0] = e0;
|
||||
result.i64[1] = e1;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_setzero_si128(void)
|
||||
{
|
||||
__m128i result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Extract/insert operations */
|
||||
static inline int _mm_cvtsi128_si32(__m128i a)
|
||||
{
|
||||
return a.i32[0];
|
||||
}
|
||||
|
||||
static inline int64_t _mm_cvtsi128_si64(__m128i a)
|
||||
{
|
||||
return a.i64[0];
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cvtsi32_si128(int a)
|
||||
{
|
||||
__m128i result = _mm_setzero_si128();
|
||||
result.i32[0] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cvtsi64_si128(int64_t a)
|
||||
{
|
||||
__m128i result = _mm_setzero_si128();
|
||||
result.i64[0] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Shuffle operations */
|
||||
static inline __m128i _mm_shuffle_epi32(__m128i a, int imm8)
|
||||
{
|
||||
__m128i result;
|
||||
result.u32[0] = a.u32[(imm8 >> 0) & 0x3];
|
||||
result.u32[1] = a.u32[(imm8 >> 2) & 0x3];
|
||||
result.u32[2] = a.u32[(imm8 >> 4) & 0x3];
|
||||
result.u32[3] = a.u32[(imm8 >> 6) & 0x3];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Logical operations */
|
||||
static inline __m128i _mm_xor_si128(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] ^ b.u64[0];
|
||||
result.u64[1] = a.u64[1] ^ b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_or_si128(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] | b.u64[0];
|
||||
result.u64[1] = a.u64[1] | b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_and_si128(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] & b.u64[0];
|
||||
result.u64[1] = a.u64[1] & b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_andnot_si128(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = (~a.u64[0]) & b.u64[0];
|
||||
result.u64[1] = (~a.u64[1]) & b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Shift operations */
|
||||
static inline __m128i _mm_slli_si128(__m128i a, int imm8)
|
||||
{
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
for (int i = 0; i < 16 - count; i++) {
|
||||
result.u8[i + count] = a.u8[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_srli_si128(__m128i a, int imm8)
|
||||
{
|
||||
__m128i result = _mm_setzero_si128();
|
||||
int count = imm8 & 0xFF;
|
||||
if (count > 15) return result;
|
||||
|
||||
for (int i = count; i < 16; i++) {
|
||||
result.u8[i - count] = a.u8[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_slli_epi64(__m128i a, int imm8)
|
||||
{
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
result.u64[0] = a.u64[0] << imm8;
|
||||
result.u64[1] = a.u64[1] << imm8;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_srli_epi64(__m128i a, int imm8)
|
||||
{
|
||||
__m128i result;
|
||||
if (imm8 > 63) {
|
||||
result.u64[0] = 0;
|
||||
result.u64[1] = 0;
|
||||
} else {
|
||||
result.u64[0] = a.u64[0] >> imm8;
|
||||
result.u64[1] = a.u64[1] >> imm8;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Load/store operations */
|
||||
static inline __m128i _mm_load_si128(const __m128i* p)
|
||||
{
|
||||
__m128i result;
|
||||
memcpy(&result, p, sizeof(__m128i));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_loadu_si128(const __m128i* p)
|
||||
{
|
||||
__m128i result;
|
||||
memcpy(&result, p, sizeof(__m128i));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void _mm_store_si128(__m128i* p, __m128i a)
|
||||
{
|
||||
memcpy(p, &a, sizeof(__m128i));
|
||||
}
|
||||
|
||||
static inline void _mm_storeu_si128(__m128i* p, __m128i a)
|
||||
{
|
||||
memcpy(p, &a, sizeof(__m128i));
|
||||
}
|
||||
|
||||
/* Arithmetic operations */
|
||||
static inline __m128i _mm_add_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] + b.u64[0];
|
||||
result.u64[1] = a.u64[1] + b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_add_epi32(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.i32[i] = a.i32[i] + b.i32[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_sub_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0] - b.u64[0];
|
||||
result.u64[1] = a.u64[1] - b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_mul_epu32(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = (uint64_t)a.u32[0] * (uint64_t)b.u32[0];
|
||||
result.u64[1] = (uint64_t)a.u32[2] * (uint64_t)b.u32[2];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Unpack operations */
|
||||
static inline __m128i _mm_unpacklo_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[0];
|
||||
result.u64[1] = b.u64[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_unpackhi_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
result.u64[0] = a.u64[1];
|
||||
result.u64[1] = b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Pause instruction for spin-wait loops */
|
||||
static inline void _mm_pause(void)
|
||||
{
|
||||
/* RISC-V doesn't have a direct equivalent to x86 PAUSE
|
||||
* Use a simple NOP or yield hint */
|
||||
__asm__ __volatile__("nop");
|
||||
}
|
||||
|
||||
/* Memory fence */
|
||||
static inline void _mm_mfence(void)
|
||||
{
|
||||
__asm__ __volatile__("fence" ::: "memory");
|
||||
}
|
||||
|
||||
static inline void _mm_lfence(void)
|
||||
{
|
||||
__asm__ __volatile__("fence r,r" ::: "memory");
|
||||
}
|
||||
|
||||
static inline void _mm_sfence(void)
|
||||
{
|
||||
__asm__ __volatile__("fence w,w" ::: "memory");
|
||||
}
|
||||
|
||||
/* Comparison operations */
|
||||
static inline __m128i _mm_cmpeq_epi32(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = (a.u32[i] == b.u32[i]) ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cmpeq_epi64(__m128i a, __m128i b)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
result.u64[i] = (a.u64[i] == b.u64[i]) ? 0xFFFFFFFFFFFFFFFFULL : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Additional shift operations */
|
||||
static inline __m128i _mm_slli_epi32(__m128i a, int imm8)
|
||||
{
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
for (int i = 0; i < 4; i++) result.u32[i] = 0;
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = a.u32[i] << imm8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_srli_epi32(__m128i a, int imm8)
|
||||
{
|
||||
__m128i result;
|
||||
if (imm8 > 31) {
|
||||
for (int i = 0; i < 4; i++) result.u32[i] = 0;
|
||||
} else {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = a.u32[i] >> imm8;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 64-bit integer operations */
|
||||
static inline __m128i _mm_set1_epi64x(int64_t a)
|
||||
{
|
||||
__m128i result;
|
||||
result.i64[0] = a;
|
||||
result.i64[1] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Float type for compatibility - we'll treat it as int for simplicity */
|
||||
typedef __m128i __m128;
|
||||
|
||||
/* Float operations - simplified scalar implementations */
|
||||
static inline __m128 _mm_set1_ps(float a)
|
||||
{
|
||||
__m128 result;
|
||||
uint32_t val;
|
||||
memcpy(&val, &a, sizeof(float));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.u32[i] = val;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_setzero_ps(void)
|
||||
{
|
||||
__m128 result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_add_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
float fa[4], fb[4], fr[4];
|
||||
memcpy(fa, &a, sizeof(__m128));
|
||||
memcpy(fb, &b, sizeof(__m128));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fr[i] = fa[i] + fb[i];
|
||||
}
|
||||
memcpy(&result, fr, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_mul_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
float fa[4], fb[4], fr[4];
|
||||
memcpy(fa, &a, sizeof(__m128));
|
||||
memcpy(fb, &b, sizeof(__m128));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fr[i] = fa[i] * fb[i];
|
||||
}
|
||||
memcpy(&result, fr, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_and_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
result.u64[0] = a.u64[0] & b.u64[0];
|
||||
result.u64[1] = a.u64[1] & b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_or_ps(__m128 a, __m128 b)
|
||||
{
|
||||
__m128 result;
|
||||
result.u64[0] = a.u64[0] | b.u64[0];
|
||||
result.u64[1] = a.u64[1] | b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128 _mm_cvtepi32_ps(__m128i a)
|
||||
{
|
||||
__m128 result;
|
||||
float fr[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
fr[i] = (float)a.i32[i];
|
||||
}
|
||||
memcpy(&result, fr, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_cvttps_epi32(__m128 a)
|
||||
{
|
||||
__m128i result;
|
||||
float fa[4];
|
||||
memcpy(fa, &a, sizeof(__m128));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.i32[i] = (int32_t)fa[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Casting operations */
|
||||
static inline __m128 _mm_castsi128_ps(__m128i a)
|
||||
{
|
||||
__m128 result;
|
||||
memcpy(&result, &a, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline __m128i _mm_castps_si128(__m128 a)
|
||||
{
|
||||
__m128i result;
|
||||
memcpy(&result, &a, sizeof(__m128));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Additional set operations */
|
||||
static inline __m128i _mm_set1_epi32(int a)
|
||||
{
|
||||
__m128i result;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result.i32[i] = a;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* AES instructions - these are placeholders, actual AES is done via soft_aes.h */
|
||||
/* On RISC-V without crypto extensions, these should never be called directly */
|
||||
/* They are only here for compilation compatibility */
|
||||
static inline __m128i _mm_aesenc_si128(__m128i a, __m128i roundkey)
|
||||
{
|
||||
/* This is a placeholder - actual implementation should use soft_aes */
|
||||
/* If this function is called, it means SOFT_AES template parameter wasn't used */
|
||||
/* We return a XOR as a minimal fallback, but proper code should use soft_aesenc */
|
||||
return _mm_xor_si128(a, roundkey);
|
||||
}
|
||||
|
||||
static inline __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon)
|
||||
{
|
||||
/* Placeholder for AES key generation - should use soft_aeskeygenassist */
|
||||
return a;
|
||||
}
|
||||
|
||||
/* Rotate right operation for soft_aes.h */
|
||||
static inline uint32_t _rotr(uint32_t value, unsigned int count)
|
||||
{
|
||||
const unsigned int mask = 31;
|
||||
count &= mask;
|
||||
return (value >> count) | (value << ((-count) & mask));
|
||||
}
|
||||
|
||||
/* ARM NEON compatibility types and intrinsics for RISC-V */
|
||||
typedef __m128i_union uint64x2_t;
|
||||
typedef __m128i_union uint8x16_t;
|
||||
typedef __m128i_union int64x2_t;
|
||||
typedef __m128i_union int32x4_t;
|
||||
|
||||
static inline uint64x2_t vld1q_u64(const uint64_t *ptr)
|
||||
{
|
||||
uint64x2_t result;
|
||||
result.u64[0] = ptr[0];
|
||||
result.u64[1] = ptr[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int64x2_t vld1q_s64(const int64_t *ptr)
|
||||
{
|
||||
int64x2_t result;
|
||||
result.i64[0] = ptr[0];
|
||||
result.i64[1] = ptr[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void vst1q_u64(uint64_t *ptr, uint64x2_t val)
|
||||
{
|
||||
ptr[0] = val.u64[0];
|
||||
ptr[1] = val.u64[1];
|
||||
}
|
||||
|
||||
static inline uint64x2_t veorq_u64(uint64x2_t a, uint64x2_t b)
|
||||
{
|
||||
uint64x2_t result;
|
||||
result.u64[0] = a.u64[0] ^ b.u64[0];
|
||||
result.u64[1] = a.u64[1] ^ b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64x2_t vaddq_u64(uint64x2_t a, uint64x2_t b)
|
||||
{
|
||||
uint64x2_t result;
|
||||
result.u64[0] = a.u64[0] + b.u64[0];
|
||||
result.u64[1] = a.u64[1] + b.u64[1];
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64x2_t vreinterpretq_u64_u8(uint8x16_t a)
|
||||
{
|
||||
uint64x2_t result;
|
||||
memcpy(&result, &a, sizeof(uint64x2_t));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64_t vgetq_lane_u64(uint64x2_t v, int lane)
|
||||
{
|
||||
return v.u64[lane];
|
||||
}
|
||||
|
||||
static inline int64_t vgetq_lane_s64(int64x2_t v, int lane)
|
||||
{
|
||||
return v.i64[lane];
|
||||
}
|
||||
|
||||
static inline int32_t vgetq_lane_s32(int32x4_t v, int lane)
|
||||
{
|
||||
return v.i32[lane];
|
||||
}
|
||||
|
||||
typedef struct { uint64_t val[1]; } uint64x1_t;
|
||||
|
||||
static inline uint64x1_t vcreate_u64(uint64_t a)
|
||||
{
|
||||
uint64x1_t result;
|
||||
result.val[0] = a;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint64x2_t vcombine_u64(uint64x1_t low, uint64x1_t high)
|
||||
{
|
||||
uint64x2_t result;
|
||||
result.u64[0] = low.val[0];
|
||||
result.u64[1] = high.val[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XMRIG_SSE2RVV_H */
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -35,15 +35,69 @@ constexpr size_t twoMiB = 2U * 1024U * 1024U;
|
||||
constexpr size_t oneGiB = 1024U * 1024U * 1024U;
|
||||
|
||||
|
||||
static inline std::string sysfs_path(uint32_t node, size_t hugePageSize, bool nr)
|
||||
static bool sysfs_write(const std::string &path, uint64_t value)
|
||||
{
|
||||
std::ofstream file(path, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||
if (!file.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
file << value;
|
||||
file.flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static int64_t sysfs_read(const std::string &path)
|
||||
{
|
||||
std::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t value = 0;
|
||||
file >> value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
static std::string sysfs_path(uint32_t node, size_t hugePageSize, bool nr)
|
||||
{
|
||||
return fmt::format("/sys/devices/system/node/node{}/hugepages/hugepages-{}kB/{}_hugepages", node, hugePageSize / 1024, nr ? "nr" : "free");
|
||||
}
|
||||
|
||||
|
||||
static inline bool write_nr_hugepages(uint32_t node, size_t hugePageSize, uint64_t count) { return LinuxMemory::write(sysfs_path(node, hugePageSize, true).c_str(), count); }
|
||||
static inline int64_t free_hugepages(uint32_t node, size_t hugePageSize) { return LinuxMemory::read(sysfs_path(node, hugePageSize, false).c_str()); }
|
||||
static inline int64_t nr_hugepages(uint32_t node, size_t hugePageSize) { return LinuxMemory::read(sysfs_path(node, hugePageSize, true).c_str()); }
|
||||
static std::string sysfs_path(size_t hugePageSize, bool nr)
|
||||
{
|
||||
return fmt::format("/sys/kernel/mm/hugepages/hugepages-{}kB/{}_hugepages", hugePageSize / 1024, nr ? "nr" : "free");
|
||||
}
|
||||
|
||||
|
||||
static bool write_nr_hugepages(uint32_t node, size_t hugePageSize, uint64_t count)
|
||||
{
|
||||
if (sysfs_write(sysfs_path(node, hugePageSize, true), count)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return sysfs_write(sysfs_path(hugePageSize, true), count);
|
||||
}
|
||||
|
||||
|
||||
static int64_t sysfs_read_hugepages(uint32_t node, size_t hugePageSize, bool nr)
|
||||
{
|
||||
const int64_t value = sysfs_read(sysfs_path(node, hugePageSize, nr));
|
||||
if (value >= 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return sysfs_read(sysfs_path(hugePageSize, nr));
|
||||
}
|
||||
|
||||
|
||||
static inline int64_t free_hugepages(uint32_t node, size_t hugePageSize) { return sysfs_read_hugepages(node, hugePageSize, false); }
|
||||
static inline int64_t nr_hugepages(uint32_t node, size_t hugePageSize) { return sysfs_read_hugepages(node, hugePageSize, true); }
|
||||
|
||||
|
||||
} // namespace xmrig
|
||||
@@ -62,31 +116,3 @@ bool xmrig::LinuxMemory::reserve(size_t size, uint32_t node, size_t hugePageSize
|
||||
|
||||
return write_nr_hugepages(node, hugePageSize, std::max<size_t>(nr_hugepages(node, hugePageSize), 0) + (required - available));
|
||||
}
|
||||
|
||||
|
||||
bool xmrig::LinuxMemory::write(const char *path, uint64_t value)
|
||||
{
|
||||
std::ofstream file(path, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||
if (!file.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
file << value;
|
||||
file.flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int64_t xmrig::LinuxMemory::read(const char *path)
|
||||
{
|
||||
std::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t value = 0;
|
||||
file >> value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* XMRig
|
||||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
||||
* Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
|
||||
* Copyright (c) 2016-2025 XMRig <https://github.com/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
|
||||
@@ -31,13 +31,10 @@ class LinuxMemory
|
||||
{
|
||||
public:
|
||||
static bool reserve(size_t size, uint32_t node, size_t hugePageSize);
|
||||
|
||||
static bool write(const char *path, uint64_t value);
|
||||
static int64_t read(const char *path);
|
||||
};
|
||||
|
||||
|
||||
} /* namespace xmrig */
|
||||
} // namespace xmrig
|
||||
|
||||
|
||||
#endif /* XMRIG_LINUXMEMORY_H */
|
||||
#endif // XMRIG_LINUXMEMORY_H
|
||||
|
||||
@@ -86,7 +86,7 @@ bool xmrig::VirtualMemory::isHugepagesAvailable()
|
||||
{
|
||||
# ifdef XMRIG_OS_LINUX
|
||||
return std::ifstream("/proc/sys/vm/nr_hugepages").good() || std::ifstream("/sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages").good();
|
||||
# elif defined(XMRIG_OS_MACOS) && defined(XMRIG_ARM)
|
||||
# elif defined(XMRIG_OS_MACOS) && defined(XMRIG_ARM) || defined(XMRIG_OS_HAIKU)
|
||||
return false;
|
||||
# else
|
||||
return true;
|
||||
@@ -156,7 +156,8 @@ void *xmrig::VirtualMemory::allocateExecutableMemory(size_t size, bool hugePages
|
||||
if (!mem) {
|
||||
mem = mmap(0, size, PROT_READ | PROT_WRITE | SECURE_PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
}
|
||||
|
||||
# elif defined(XMRIG_OS_HAIKU)
|
||||
void *mem = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
# else
|
||||
|
||||
void *mem = nullptr;
|
||||
@@ -181,6 +182,8 @@ void *xmrig::VirtualMemory::allocateLargePagesMemory(size_t size)
|
||||
void *mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
|
||||
# elif defined(XMRIG_OS_FREEBSD)
|
||||
void *mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER | MAP_PREFAULT_READ, -1, 0);
|
||||
# elif defined(XMRIG_OS_HAIKU)
|
||||
void *mem = nullptr;
|
||||
# else
|
||||
void *mem = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE | hugePagesFlag(hugePageSize()), 0, 0);
|
||||
# endif
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define XMRIG_MM_MALLOC_PORTABLE_H
|
||||
|
||||
|
||||
#if defined(XMRIG_ARM) && !defined(__clang__)
|
||||
#if (defined(XMRIG_ARM) || defined(XMRIG_RISCV)) && !defined(__clang__)
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
|
||||
#if defined(XMRIG_ARM)
|
||||
# include "crypto/cn/sse2neon.h"
|
||||
#elif defined(XMRIG_RISCV)
|
||||
// RISC-V doesn't have SSE/NEON, provide minimal compatibility
|
||||
# define _mm_pause() __asm__ __volatile__("nop")
|
||||
#elif defined(__GNUC__)
|
||||
# include <x86intrin.h>
|
||||
#else
|
||||
@@ -286,7 +289,7 @@ struct HelperThread
|
||||
|
||||
void benchmark()
|
||||
{
|
||||
#ifndef XMRIG_ARM
|
||||
#if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
|
||||
static std::atomic<int> done{ 0 };
|
||||
if (done.exchange(1)) {
|
||||
return;
|
||||
@@ -478,7 +481,7 @@ static inline bool findByType(hwloc_obj_t obj, hwloc_obj_type_t type, func lambd
|
||||
|
||||
HelperThread* create_helper_thread(int64_t cpu_index, int priority, const std::vector<int64_t>& affinities)
|
||||
{
|
||||
#ifndef XMRIG_ARM
|
||||
#if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
|
||||
hwloc_bitmap_t helper_cpu_set = hwloc_bitmap_alloc();
|
||||
hwloc_bitmap_t main_threads_set = hwloc_bitmap_alloc();
|
||||
|
||||
@@ -807,7 +810,7 @@ void hash_octa(const uint8_t* data, size_t size, uint8_t* output, cryptonight_ct
|
||||
uint32_t cn_indices[6];
|
||||
select_indices(cn_indices, seed);
|
||||
|
||||
#ifdef XMRIG_ARM
|
||||
#if defined(XMRIG_ARM) || defined(XMRIG_RISCV)
|
||||
uint32_t step[6] = { 1, 1, 1, 1, 1, 1 };
|
||||
#else
|
||||
uint32_t step[6] = { 4, 4, 1, 2, 4, 4 };
|
||||
|
||||
@@ -111,6 +111,10 @@ namespace randomx {
|
||||
#define RANDOMX_HAVE_COMPILER 1
|
||||
class JitCompilerA64;
|
||||
using JitCompiler = JitCompilerA64;
|
||||
#elif defined(__riscv) && defined(__riscv_xlen) && (__riscv_xlen == 64)
|
||||
#define RANDOMX_HAVE_COMPILER 1
|
||||
class JitCompilerRV64;
|
||||
using JitCompiler = JitCompilerRV64;
|
||||
#else
|
||||
#define RANDOMX_HAVE_COMPILER 0
|
||||
class JitCompilerFallback;
|
||||
|
||||
@@ -32,6 +32,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "crypto/randomx/jit_compiler_x86.hpp"
|
||||
#elif defined(__aarch64__)
|
||||
#include "crypto/randomx/jit_compiler_a64.hpp"
|
||||
#elif defined(__riscv) && defined(__riscv_xlen) && (__riscv_xlen == 64)
|
||||
#include "crypto/randomx/jit_compiler_rv64.hpp"
|
||||
#else
|
||||
#include "crypto/randomx/jit_compiler_fallback.hpp"
|
||||
#endif
|
||||
|
||||
@@ -67,7 +67,6 @@ constexpr uint32_t LDR_LITERAL = 0x58000000;
|
||||
constexpr uint32_t ROR = 0x9AC02C00;
|
||||
constexpr uint32_t ROR_IMM = 0x93C00000;
|
||||
constexpr uint32_t MOV_REG = 0xAA0003E0;
|
||||
constexpr uint32_t MOV_VREG_EL = 0x6E080400;
|
||||
constexpr uint32_t FADD = 0x4E60D400;
|
||||
constexpr uint32_t FSUB = 0x4EE0D400;
|
||||
constexpr uint32_t FEOR = 0x6E201C00;
|
||||
@@ -102,7 +101,7 @@ static size_t CalcDatasetItemSize()
|
||||
((uint8_t*)randomx_calc_dataset_item_aarch64_end - (uint8_t*)randomx_calc_dataset_item_aarch64_store_result);
|
||||
}
|
||||
|
||||
constexpr uint32_t IntRegMap[8] = { 4, 5, 6, 7, 12, 13, 14, 15 };
|
||||
constexpr uint8_t IntRegMap[8] = { 4, 5, 6, 7, 12, 13, 14, 15 };
|
||||
|
||||
JitCompilerA64::JitCompilerA64(bool hugePagesEnable, bool) :
|
||||
hugePages(hugePagesJIT && hugePagesEnable),
|
||||
@@ -128,11 +127,12 @@ void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& con
|
||||
|
||||
uint32_t codePos = MainLoopBegin + 4;
|
||||
|
||||
uint32_t mask = ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 7) << 10);
|
||||
// and w16, w10, ScratchpadL3Mask64
|
||||
emit32(0x121A0000 | 16 | (10 << 5) | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 7) << 10), code, codePos);
|
||||
emit32(0x121A0000 | 16 | (10 << 5) | mask, code, codePos);
|
||||
|
||||
// and w17, w20, ScratchpadL3Mask64
|
||||
emit32(0x121A0000 | 17 | (20 << 5) | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 7) << 10), code, codePos);
|
||||
emit32(0x121A0000 | 17 | (20 << 5) | mask, code, codePos);
|
||||
|
||||
codePos = PrologueSize;
|
||||
literalPos = ImulRcpLiteralsEnd;
|
||||
@@ -155,13 +155,14 @@ void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& con
|
||||
const uint32_t offset = (((uint8_t*)randomx_program_aarch64_vm_instructions_end) - ((uint8_t*)randomx_program_aarch64)) - codePos;
|
||||
emit32(ARMV8A::B | (offset / 4), code, codePos);
|
||||
|
||||
// and w20, w20, CacheLineAlignMask
|
||||
mask = ((RandomX_CurrentConfig.Log2_DatasetBaseSize - 7) << 10);
|
||||
// and w20, w9, CacheLineAlignMask
|
||||
codePos = (((uint8_t*)randomx_program_aarch64_cacheline_align_mask1) - ((uint8_t*)randomx_program_aarch64));
|
||||
emit32(0x121A0000 | 20 | (20 << 5) | ((RandomX_CurrentConfig.Log2_DatasetBaseSize - 7) << 10), code, codePos);
|
||||
emit32(0x121A0000 | 20 | (9 << 5) | mask, code, codePos);
|
||||
|
||||
// and w10, w10, CacheLineAlignMask
|
||||
codePos = (((uint8_t*)randomx_program_aarch64_cacheline_align_mask2) - ((uint8_t*)randomx_program_aarch64));
|
||||
emit32(0x121A0000 | 10 | (10 << 5) | ((RandomX_CurrentConfig.Log2_DatasetBaseSize - 7) << 10), code, codePos);
|
||||
emit32(0x121A0000 | 10 | (10 << 5) | mask, code, codePos);
|
||||
|
||||
// Update spMix1
|
||||
// eor x10, config.readReg0, config.readReg1
|
||||
@@ -497,9 +498,12 @@ void JitCompilerA64::emitMemLoad(uint32_t dst, uint32_t src, Instruction& instr,
|
||||
if (src != dst)
|
||||
{
|
||||
imm &= instr.getModMem() ? (RandomX_CurrentConfig.ScratchpadL1_Size - 1) : (RandomX_CurrentConfig.ScratchpadL2_Size - 1);
|
||||
emitAddImmediate(tmp_reg, src, imm, code, k);
|
||||
uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
|
||||
if (imm)
|
||||
emitAddImmediate(tmp_reg, src, imm, code, k);
|
||||
else
|
||||
t = 0x927d0000 | tmp_reg | (src << 5);
|
||||
|
||||
constexpr uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
|
||||
const uint32_t andInstrL1 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL1 - 4) << 10);
|
||||
const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10);
|
||||
|
||||
@@ -511,10 +515,18 @@ void JitCompilerA64::emitMemLoad(uint32_t dst, uint32_t src, Instruction& instr,
|
||||
else
|
||||
{
|
||||
imm = (imm & ScratchpadL3Mask) >> 3;
|
||||
emitMovImmediate(tmp_reg, imm, code, k);
|
||||
if (imm)
|
||||
{
|
||||
emitMovImmediate(tmp_reg, imm, code, k);
|
||||
|
||||
// ldr tmp_reg, [x2, tmp_reg, lsl 3]
|
||||
emit32(0xf8607840 | tmp_reg | (tmp_reg << 16), code, k);
|
||||
// ldr tmp_reg, [x2, tmp_reg, lsl 3]
|
||||
emit32(0xf8607840 | tmp_reg | (tmp_reg << 16), code, k);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ldr tmp_reg, [x2]
|
||||
emit32(0xf9400040 | tmp_reg, code, k);
|
||||
}
|
||||
}
|
||||
|
||||
codePos = k;
|
||||
@@ -529,25 +541,22 @@ void JitCompilerA64::emitMemLoadFP(uint32_t src, Instruction& instr, uint8_t* co
|
||||
constexpr uint32_t tmp_reg = 19;
|
||||
|
||||
imm &= instr.getModMem() ? (RandomX_CurrentConfig.ScratchpadL1_Size - 1) : (RandomX_CurrentConfig.ScratchpadL2_Size - 1);
|
||||
emitAddImmediate(tmp_reg, src, imm, code, k);
|
||||
uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
|
||||
if (imm)
|
||||
emitAddImmediate(tmp_reg, src, imm, code, k);
|
||||
else
|
||||
t = 0x927d0000 | tmp_reg | (src << 5);
|
||||
|
||||
constexpr uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
|
||||
const uint32_t andInstrL1 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL1 - 4) << 10);
|
||||
const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10);
|
||||
|
||||
emit32(instr.getModMem() ? andInstrL1 : andInstrL2, code, k);
|
||||
|
||||
// add tmp_reg, x2, tmp_reg
|
||||
emit32(ARMV8A::ADD | tmp_reg | (2 << 5) | (tmp_reg << 16), code, k);
|
||||
// ldr tmp_reg_fp, [x2, tmp_reg]
|
||||
emit32(0x3ce06800 | tmp_reg_fp | (2 << 5) | (tmp_reg << 16), code, k);
|
||||
|
||||
// ldpsw tmp_reg, tmp_reg + 1, [tmp_reg]
|
||||
emit32(0x69400000 | tmp_reg | (tmp_reg << 5) | ((tmp_reg + 1) << 10), code, k);
|
||||
|
||||
// ins tmp_reg_fp.d[0], tmp_reg
|
||||
emit32(0x4E081C00 | tmp_reg_fp | (tmp_reg << 5), code, k);
|
||||
|
||||
// ins tmp_reg_fp.d[1], tmp_reg + 1
|
||||
emit32(0x4E181C00 | tmp_reg_fp | ((tmp_reg + 1) << 5), code, k);
|
||||
// sxtl.2d tmp_reg_fp, tmp_reg_fp
|
||||
emit32(0x0f20a400 | tmp_reg_fp | (tmp_reg_fp << 5), code, k);
|
||||
|
||||
// scvtf tmp_reg_fp.2d, tmp_reg_fp.2d
|
||||
emit32(0x4E61D800 | tmp_reg_fp | (tmp_reg_fp << 5), code, k);
|
||||
@@ -835,7 +844,8 @@ void JitCompilerA64::h_IROR_R(Instruction& instr, uint32_t& codePos)
|
||||
else
|
||||
{
|
||||
// ror dst, dst, imm
|
||||
emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((instr.getImm32() & 63) << 10) | (dst << 16), code, codePos);
|
||||
if ((instr.getImm32() & 63))
|
||||
emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((instr.getImm32() & 63) << 10) | (dst << 16), code, codePos);
|
||||
}
|
||||
|
||||
reg_changed_offset[instr.dst] = codePos;
|
||||
@@ -861,7 +871,8 @@ void JitCompilerA64::h_IROL_R(Instruction& instr, uint32_t& codePos)
|
||||
else
|
||||
{
|
||||
// ror dst, dst, imm
|
||||
emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((-instr.getImm32() & 63) << 10) | (dst << 16), code, k);
|
||||
if ((instr.getImm32() & 63))
|
||||
emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((-instr.getImm32() & 63) << 10) | (dst << 16), code, k);
|
||||
}
|
||||
|
||||
reg_changed_offset[instr.dst] = k;
|
||||
@@ -894,13 +905,8 @@ void JitCompilerA64::h_FSWAP_R(Instruction& instr, uint32_t& codePos)
|
||||
|
||||
const uint32_t dst = instr.dst + 16;
|
||||
|
||||
constexpr uint32_t tmp_reg_fp = 28;
|
||||
constexpr uint32_t src_index1 = 1 << 14;
|
||||
constexpr uint32_t dst_index1 = 1 << 20;
|
||||
|
||||
emit32(ARMV8A::MOV_VREG_EL | tmp_reg_fp | (dst << 5) | src_index1, code, k);
|
||||
emit32(ARMV8A::MOV_VREG_EL | dst | (dst << 5) | dst_index1, code, k);
|
||||
emit32(ARMV8A::MOV_VREG_EL | dst | (tmp_reg_fp << 5), code, k);
|
||||
// ext dst.16b, dst.16b, dst.16b, #0x8
|
||||
emit32(0x6e004000 | dst | (dst << 5) | (dst << 16), code, k);
|
||||
|
||||
codePos = k;
|
||||
}
|
||||
@@ -1029,11 +1035,19 @@ void JitCompilerA64::h_CFROUND(Instruction& instr, uint32_t& codePos)
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
constexpr uint32_t fpcr_tmp_reg = 8;
|
||||
|
||||
// ror tmp_reg, src, imm
|
||||
emit32(ARMV8A::ROR_IMM | tmp_reg | (src << 5) | ((instr.getImm32() & 63) << 10) | (src << 16), code, k);
|
||||
if (instr.getImm32() & 63)
|
||||
{
|
||||
// ror tmp_reg, src, imm
|
||||
emit32(ARMV8A::ROR_IMM | tmp_reg | (src << 5) | ((instr.getImm32() & 63) << 10) | (src << 16), code, k);
|
||||
|
||||
// bfi fpcr_tmp_reg, tmp_reg, 40, 2
|
||||
emit32(0xB3580400 | fpcr_tmp_reg | (tmp_reg << 5), code, k);
|
||||
// bfi fpcr_tmp_reg, tmp_reg, 40, 2
|
||||
emit32(0xB3580400 | fpcr_tmp_reg | (tmp_reg << 5), code, k);
|
||||
}
|
||||
else // no rotation
|
||||
{
|
||||
// bfi fpcr_tmp_reg, src, 40, 2
|
||||
emit32(0xB3580400 | fpcr_tmp_reg | (src << 5), code, k);
|
||||
}
|
||||
|
||||
// rbit tmp_reg, fpcr_tmp_reg
|
||||
emit32(0xDAC00000 | tmp_reg | (fpcr_tmp_reg << 5), code, k);
|
||||
@@ -1059,9 +1073,12 @@ void JitCompilerA64::h_ISTORE(Instruction& instr, uint32_t& codePos)
|
||||
else
|
||||
imm &= RandomX_CurrentConfig.ScratchpadL3_Size - 1;
|
||||
|
||||
emitAddImmediate(tmp_reg, dst, imm, code, k);
|
||||
uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
|
||||
if (imm)
|
||||
emitAddImmediate(tmp_reg, dst, imm, code, k);
|
||||
else
|
||||
t = 0x927d0000 | tmp_reg | (dst << 5);
|
||||
|
||||
constexpr uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
|
||||
const uint32_t andInstrL1 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL1 - 4) << 10);
|
||||
const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10);
|
||||
const uint32_t andInstrL3 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 4) << 10);
|
||||
|
||||
@@ -100,9 +100,9 @@
|
||||
# v26 -> "a2"
|
||||
# v27 -> "a3"
|
||||
# v28 -> temporary
|
||||
# v29 -> E 'and' mask = 0x00ffffffffffffff00ffffffffffffff
|
||||
# v30 -> E 'or' mask = 0x3*00000000******3*00000000******
|
||||
# v31 -> scale mask = 0x81f000000000000081f0000000000000
|
||||
# v29 -> E 'and' mask = 0x00ffffffffffffff'00ffffffffffffff
|
||||
# v30 -> E 'or' mask = 0x3*00000000******'3*00000000******
|
||||
# v31 -> scale mask = 0x80f0000000000000'80f0000000000000
|
||||
|
||||
.balign 4
|
||||
DECL(randomx_program_aarch64):
|
||||
@@ -142,17 +142,14 @@ DECL(randomx_program_aarch64):
|
||||
ldp q26, q27, [x0, 224]
|
||||
|
||||
# Load E 'and' mask
|
||||
mov x16, 0x00FFFFFFFFFFFFFF
|
||||
ins v29.d[0], x16
|
||||
ins v29.d[1], x16
|
||||
movi v29.2d, #0x00FFFFFFFFFFFFFF
|
||||
|
||||
# Load E 'or' mask (stored in reg.f[0])
|
||||
ldr q30, [x0, 64]
|
||||
|
||||
# Load scale mask
|
||||
mov x16, 0x80f0000000000000
|
||||
ins v31.d[0], x16
|
||||
ins v31.d[1], x16
|
||||
dup v31.2d, x16
|
||||
|
||||
# Read fpcr
|
||||
mrs x8, fpcr
|
||||
@@ -162,35 +159,22 @@ DECL(randomx_program_aarch64):
|
||||
str x0, [sp, -16]!
|
||||
|
||||
# Read literals
|
||||
ldr x0, literal_x0
|
||||
ldr x11, literal_x11
|
||||
ldr x21, literal_x21
|
||||
ldr x22, literal_x22
|
||||
ldr x23, literal_x23
|
||||
ldr x24, literal_x24
|
||||
ldr x25, literal_x25
|
||||
ldr x26, literal_x26
|
||||
ldr x27, literal_x27
|
||||
ldr x28, literal_x28
|
||||
ldr x29, literal_x29
|
||||
ldr x30, literal_x30
|
||||
adr x30, literal_v0
|
||||
ldp q0, q1, [x30]
|
||||
ldp q2, q3, [x30, 32]
|
||||
ldp q4, q5, [x30, 64]
|
||||
ldp q6, q7, [x30, 96]
|
||||
ldp q8, q9, [x30, 128]
|
||||
ldp q10, q11, [x30, 160]
|
||||
ldp q12, q13, [x30, 192]
|
||||
ldp q14, q15, [x30, 224]
|
||||
|
||||
ldr q0, literal_v0
|
||||
ldr q1, literal_v1
|
||||
ldr q2, literal_v2
|
||||
ldr q3, literal_v3
|
||||
ldr q4, literal_v4
|
||||
ldr q5, literal_v5
|
||||
ldr q6, literal_v6
|
||||
ldr q7, literal_v7
|
||||
ldr q8, literal_v8
|
||||
ldr q9, literal_v9
|
||||
ldr q10, literal_v10
|
||||
ldr q11, literal_v11
|
||||
ldr q12, literal_v12
|
||||
ldr q13, literal_v13
|
||||
ldr q14, literal_v14
|
||||
ldr q15, literal_v15
|
||||
ldp x0, x11, [x30, -96] // literal_x0
|
||||
ldp x21, x22, [x30, -80] // literal_x21
|
||||
ldp x23, x24, [x30, -64] // literal_x23
|
||||
ldp x25, x26, [x30, -48] // literal_x25
|
||||
ldp x27, x28, [x30, -32] // literal_x27
|
||||
ldp x29, x30, [x30, -16] // literal_x29
|
||||
|
||||
DECL(randomx_program_aarch64_main_loop):
|
||||
# spAddr0 = spMix1 & ScratchpadL3Mask64;
|
||||
@@ -221,40 +205,31 @@ DECL(randomx_program_aarch64_main_loop):
|
||||
eor x15, x15, x19
|
||||
|
||||
# Load group F registers (spAddr1)
|
||||
ldpsw x20, x19, [x17]
|
||||
ins v16.d[0], x20
|
||||
ins v16.d[1], x19
|
||||
ldpsw x20, x19, [x17, 8]
|
||||
ins v17.d[0], x20
|
||||
ins v17.d[1], x19
|
||||
ldpsw x20, x19, [x17, 16]
|
||||
ins v18.d[0], x20
|
||||
ins v18.d[1], x19
|
||||
ldpsw x20, x19, [x17, 24]
|
||||
ins v19.d[0], x20
|
||||
ins v19.d[1], x19
|
||||
ldr q17, [x17]
|
||||
sxtl v16.2d, v17.2s
|
||||
scvtf v16.2d, v16.2d
|
||||
sxtl2 v17.2d, v17.4s
|
||||
scvtf v17.2d, v17.2d
|
||||
|
||||
ldr q19, [x17, 16]
|
||||
sxtl v18.2d, v19.2s
|
||||
scvtf v18.2d, v18.2d
|
||||
sxtl2 v19.2d, v19.4s
|
||||
scvtf v19.2d, v19.2d
|
||||
|
||||
# Load group E registers (spAddr1)
|
||||
ldpsw x20, x19, [x17, 32]
|
||||
ins v20.d[0], x20
|
||||
ins v20.d[1], x19
|
||||
ldpsw x20, x19, [x17, 40]
|
||||
ins v21.d[0], x20
|
||||
ins v21.d[1], x19
|
||||
ldpsw x20, x19, [x17, 48]
|
||||
ins v22.d[0], x20
|
||||
ins v22.d[1], x19
|
||||
ldpsw x20, x19, [x17, 56]
|
||||
ins v23.d[0], x20
|
||||
ins v23.d[1], x19
|
||||
ldr q21, [x17, 32]
|
||||
sxtl v20.2d, v21.2s
|
||||
scvtf v20.2d, v20.2d
|
||||
sxtl2 v21.2d, v21.4s
|
||||
scvtf v21.2d, v21.2d
|
||||
|
||||
ldr q23, [x17, 48]
|
||||
sxtl v22.2d, v23.2s
|
||||
scvtf v22.2d, v22.2d
|
||||
sxtl2 v23.2d, v23.4s
|
||||
scvtf v23.2d, v23.2d
|
||||
|
||||
and v20.16b, v20.16b, v29.16b
|
||||
and v21.16b, v21.16b, v29.16b
|
||||
and v22.16b, v22.16b, v29.16b
|
||||
@@ -310,10 +285,9 @@ DECL(randomx_program_aarch64_vm_instructions_end):
|
||||
eor x9, x9, x20
|
||||
|
||||
# Calculate dataset pointer for dataset prefetch
|
||||
mov w20, w9
|
||||
DECL(randomx_program_aarch64_cacheline_align_mask1):
|
||||
# Actual mask will be inserted by JIT compiler
|
||||
and x20, x20, 1
|
||||
and x20, x9, 1
|
||||
add x20, x20, x1
|
||||
|
||||
# Prefetch dataset data
|
||||
@@ -491,42 +465,39 @@ DECL(randomx_calc_dataset_item_aarch64):
|
||||
stp x10, x11, [sp, 80]
|
||||
stp x12, x13, [sp, 96]
|
||||
|
||||
ldr x12, superscalarMul0
|
||||
adr x7, superscalarMul0
|
||||
# superscalarMul0, superscalarAdd1
|
||||
ldp x12, x13, [x7]
|
||||
|
||||
mov x8, x0
|
||||
mov x9, x1
|
||||
ldp x8, x9, [sp]
|
||||
mov x10, x2
|
||||
|
||||
# rl[0] = (itemNumber + 1) * superscalarMul0;
|
||||
madd x0, x2, x12, x12
|
||||
|
||||
# rl[1] = rl[0] ^ superscalarAdd1;
|
||||
ldr x12, superscalarAdd1
|
||||
eor x1, x0, x12
|
||||
eor x1, x0, x13
|
||||
|
||||
# rl[2] = rl[0] ^ superscalarAdd2;
|
||||
ldr x12, superscalarAdd2
|
||||
ldp x12, x13, [x7, 16]
|
||||
eor x2, x0, x12
|
||||
|
||||
# rl[3] = rl[0] ^ superscalarAdd3;
|
||||
ldr x12, superscalarAdd3
|
||||
eor x3, x0, x12
|
||||
eor x3, x0, x13
|
||||
|
||||
# rl[4] = rl[0] ^ superscalarAdd4;
|
||||
ldr x12, superscalarAdd4
|
||||
ldp x12, x13, [x7, 32]
|
||||
eor x4, x0, x12
|
||||
|
||||
# rl[5] = rl[0] ^ superscalarAdd5;
|
||||
ldr x12, superscalarAdd5
|
||||
eor x5, x0, x12
|
||||
eor x5, x0, x13
|
||||
|
||||
# rl[6] = rl[0] ^ superscalarAdd6;
|
||||
ldr x12, superscalarAdd6
|
||||
ldp x12, x13, [x7, 48]
|
||||
eor x6, x0, x12
|
||||
|
||||
# rl[7] = rl[0] ^ superscalarAdd7;
|
||||
ldr x12, superscalarAdd7
|
||||
eor x7, x0, x12
|
||||
eor x7, x0, x13
|
||||
|
||||
b DECL(randomx_calc_dataset_item_aarch64_prefetch)
|
||||
|
||||
|
||||
1164
src/crypto/randomx/jit_compiler_rv64.cpp
Normal file
1164
src/crypto/randomx/jit_compiler_rv64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
144
src/crypto/randomx/jit_compiler_rv64.hpp
Normal file
144
src/crypto/randomx/jit_compiler_rv64.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
Copyright (c) 2023 tevador <tevador@gmail.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include "crypto/randomx/common.hpp"
|
||||
#include "crypto/randomx/jit_compiler_rv64_static.hpp"
|
||||
|
||||
namespace randomx {
|
||||
|
||||
struct CodeBuffer {
|
||||
uint8_t* code;
|
||||
int32_t codePos;
|
||||
int32_t rcpCount;
|
||||
|
||||
void emit(const uint8_t* src, int32_t len) {
|
||||
memcpy(&code[codePos], src, len);
|
||||
codePos += len;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void emit(T src) {
|
||||
memcpy(&code[codePos], &src, sizeof(src));
|
||||
codePos += sizeof(src);
|
||||
}
|
||||
|
||||
void emitAt(int32_t codePos, const uint8_t* src, int32_t len) {
|
||||
memcpy(&code[codePos], src, len);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void emitAt(int32_t codePos, T src) {
|
||||
memcpy(&code[codePos], &src, sizeof(src));
|
||||
}
|
||||
};
|
||||
|
||||
struct CompilerState : public CodeBuffer {
|
||||
int32_t instructionOffsets[RANDOMX_PROGRAM_MAX_SIZE];
|
||||
int registerUsage[RegistersCount];
|
||||
};
|
||||
|
||||
class Program;
|
||||
struct ProgramConfiguration;
|
||||
class SuperscalarProgram;
|
||||
class Instruction;
|
||||
|
||||
#define HANDLER_ARGS randomx::CompilerState& state, randomx::Instruction isn, int i
|
||||
typedef void(*InstructionGeneratorRV64)(HANDLER_ARGS);
|
||||
|
||||
class JitCompilerRV64 {
|
||||
public:
|
||||
JitCompilerRV64(bool hugePagesEnable, bool optimizedInitDatasetEnable);
|
||||
~JitCompilerRV64();
|
||||
|
||||
void prepare() {}
|
||||
void generateProgram(Program&, ProgramConfiguration&, uint32_t);
|
||||
void generateProgramLight(Program&, ProgramConfiguration&, uint32_t);
|
||||
|
||||
template<size_t N>
|
||||
void generateSuperscalarHash(SuperscalarProgram(&programs)[N]);
|
||||
|
||||
void generateDatasetInitCode() {}
|
||||
|
||||
ProgramFunc* getProgramFunc() {
|
||||
return (ProgramFunc*)entryProgram;
|
||||
}
|
||||
DatasetInitFunc* getDatasetInitFunc() {
|
||||
return (DatasetInitFunc*)entryDataInit;
|
||||
}
|
||||
uint8_t* getCode() {
|
||||
return state.code;
|
||||
}
|
||||
size_t getCodeSize();
|
||||
|
||||
void enableWriting() const;
|
||||
void enableExecution() const;
|
||||
|
||||
static InstructionGeneratorRV64 engine[256];
|
||||
private:
|
||||
CompilerState state;
|
||||
void* entryDataInit;
|
||||
void* entryProgram;
|
||||
|
||||
public:
|
||||
static void v1_IADD_RS(HANDLER_ARGS);
|
||||
static void v1_IADD_M(HANDLER_ARGS);
|
||||
static void v1_ISUB_R(HANDLER_ARGS);
|
||||
static void v1_ISUB_M(HANDLER_ARGS);
|
||||
static void v1_IMUL_R(HANDLER_ARGS);
|
||||
static void v1_IMUL_M(HANDLER_ARGS);
|
||||
static void v1_IMULH_R(HANDLER_ARGS);
|
||||
static void v1_IMULH_M(HANDLER_ARGS);
|
||||
static void v1_ISMULH_R(HANDLER_ARGS);
|
||||
static void v1_ISMULH_M(HANDLER_ARGS);
|
||||
static void v1_IMUL_RCP(HANDLER_ARGS);
|
||||
static void v1_INEG_R(HANDLER_ARGS);
|
||||
static void v1_IXOR_R(HANDLER_ARGS);
|
||||
static void v1_IXOR_M(HANDLER_ARGS);
|
||||
static void v1_IROR_R(HANDLER_ARGS);
|
||||
static void v1_IROL_R(HANDLER_ARGS);
|
||||
static void v1_ISWAP_R(HANDLER_ARGS);
|
||||
static void v1_FSWAP_R(HANDLER_ARGS);
|
||||
static void v1_FADD_R(HANDLER_ARGS);
|
||||
static void v1_FADD_M(HANDLER_ARGS);
|
||||
static void v1_FSUB_R(HANDLER_ARGS);
|
||||
static void v1_FSUB_M(HANDLER_ARGS);
|
||||
static void v1_FSCAL_R(HANDLER_ARGS);
|
||||
static void v1_FMUL_R(HANDLER_ARGS);
|
||||
static void v1_FDIV_M(HANDLER_ARGS);
|
||||
static void v1_FSQRT_R(HANDLER_ARGS);
|
||||
static void v1_CBRANCH(HANDLER_ARGS);
|
||||
static void v1_CFROUND(HANDLER_ARGS);
|
||||
static void v1_ISTORE(HANDLER_ARGS);
|
||||
static void v1_NOP(HANDLER_ARGS);
|
||||
};
|
||||
}
|
||||
1236
src/crypto/randomx/jit_compiler_rv64_static.S
Normal file
1236
src/crypto/randomx/jit_compiler_rv64_static.S
Normal file
File diff suppressed because it is too large
Load Diff
53
src/crypto/randomx/jit_compiler_rv64_static.hpp
Normal file
53
src/crypto/randomx/jit_compiler_rv64_static.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright (c) 2023 tevador <tevador@gmail.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
void randomx_riscv64_literals();
|
||||
void randomx_riscv64_literals_end();
|
||||
void randomx_riscv64_data_init();
|
||||
void randomx_riscv64_fix_data_call();
|
||||
void randomx_riscv64_prologue();
|
||||
void randomx_riscv64_loop_begin();
|
||||
void randomx_riscv64_data_read();
|
||||
void randomx_riscv64_data_read_light();
|
||||
void randomx_riscv64_fix_loop_call();
|
||||
void randomx_riscv64_spad_store();
|
||||
void randomx_riscv64_spad_store_hardaes();
|
||||
void randomx_riscv64_spad_store_softaes();
|
||||
void randomx_riscv64_loop_end();
|
||||
void randomx_riscv64_fix_continue_loop();
|
||||
void randomx_riscv64_epilogue();
|
||||
void randomx_riscv64_softaes();
|
||||
void randomx_riscv64_program_end();
|
||||
void randomx_riscv64_ssh_init();
|
||||
void randomx_riscv64_ssh_load();
|
||||
void randomx_riscv64_ssh_prefetch();
|
||||
void randomx_riscv64_ssh_end();
|
||||
}
|
||||
@@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "crypto/randomx/jit_compiler_x86_static.hpp"
|
||||
#elif (XMRIG_ARM == 8)
|
||||
#include "crypto/randomx/jit_compiler_a64_static.hpp"
|
||||
#elif defined(__riscv) && defined(__riscv_xlen) && (__riscv_xlen == 64)
|
||||
#include "crypto/randomx/jit_compiler_rv64_static.hpp"
|
||||
#endif
|
||||
|
||||
#include "backend/cpu/Cpu.h"
|
||||
@@ -190,7 +192,7 @@ RandomX_ConfigurationBase::RandomX_ConfigurationBase()
|
||||
# endif
|
||||
}
|
||||
|
||||
#if (XMRIG_ARM == 8)
|
||||
#if (XMRIG_ARM == 8) || defined(XMRIG_RISCV)
|
||||
static uint32_t Log2(size_t value) { return (value > 1) ? (Log2(value / 2) + 1) : 0; }
|
||||
#endif
|
||||
|
||||
@@ -274,6 +276,14 @@ typedef void(randomx::JitCompilerX86::* InstructionGeneratorX86_2)(const randomx
|
||||
|
||||
#define JIT_HANDLE(x, prev) randomx::JitCompilerA64::engine[k] = &randomx::JitCompilerA64::h_##x
|
||||
|
||||
#elif defined(XMRIG_RISCV)
|
||||
|
||||
Log2_ScratchpadL1 = Log2(ScratchpadL1_Size);
|
||||
Log2_ScratchpadL2 = Log2(ScratchpadL2_Size);
|
||||
Log2_ScratchpadL3 = Log2(ScratchpadL3_Size);
|
||||
|
||||
#define JIT_HANDLE(x, prev) randomx::JitCompilerRV64::engine[k] = &randomx::JitCompilerRV64::v1_##x
|
||||
|
||||
#else
|
||||
#define JIT_HANDLE(x, prev)
|
||||
#endif
|
||||
|
||||
@@ -133,7 +133,7 @@ struct RandomX_ConfigurationBase
|
||||
uint32_t ScratchpadL3Mask_Calculated;
|
||||
uint32_t ScratchpadL3Mask64_Calculated;
|
||||
|
||||
# if (XMRIG_ARM == 8)
|
||||
# if (XMRIG_ARM == 8) || defined(XMRIG_RISCV)
|
||||
uint32_t Log2_ScratchpadL1;
|
||||
uint32_t Log2_ScratchpadL2;
|
||||
uint32_t Log2_ScratchpadL3;
|
||||
|
||||
9
src/crypto/randomx/tests/riscv64_zba.s
Normal file
9
src/crypto/randomx/tests/riscv64_zba.s
Normal file
@@ -0,0 +1,9 @@
|
||||
/* RISC-V - test if the Zba extension is present */
|
||||
|
||||
.text
|
||||
.global main
|
||||
|
||||
main:
|
||||
sh1add x6, x6, x7
|
||||
li x10, 0
|
||||
ret
|
||||
9
src/crypto/randomx/tests/riscv64_zbb.s
Normal file
9
src/crypto/randomx/tests/riscv64_zbb.s
Normal file
@@ -0,0 +1,9 @@
|
||||
/* RISC-V - test if the Zbb extension is present */
|
||||
|
||||
.text
|
||||
.global main
|
||||
|
||||
main:
|
||||
ror x6, x6, x7
|
||||
li x10, 0
|
||||
ret
|
||||
@@ -29,9 +29,17 @@ randomx_vm *xmrig::RxVm::create(RxDataset *dataset, uint8_t *scratchpad, bool so
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
// On RISC-V, force software AES path even if CPU reports AES capability.
|
||||
// The RandomX portable intrinsics will throw at runtime when HAVE_AES is not defined
|
||||
// for this architecture. Until native AES intrinsics are wired for RISC-V, avoid
|
||||
// setting HARD_AES to prevent "Platform doesn't support hardware AES" aborts.
|
||||
# ifndef XMRIG_RISCV
|
||||
if (!softAes) {
|
||||
flags |= RANDOMX_FLAG_HARD_AES;
|
||||
}
|
||||
# else
|
||||
(void)softAes; // unused on RISC-V to force soft AES
|
||||
# endif
|
||||
|
||||
if (dataset->get()) {
|
||||
flags |= RANDOMX_FLAG_FULL_MEM;
|
||||
|
||||
@@ -22,18 +22,20 @@
|
||||
#define APP_ID "xmrig"
|
||||
#define APP_NAME "XMRig"
|
||||
#define APP_DESC "XMRig miner"
|
||||
#define APP_VERSION "6.23.0"
|
||||
#define APP_VERSION "6.24.1-dev"
|
||||
#define APP_DOMAIN "xmrig.com"
|
||||
#define APP_SITE "www.xmrig.com"
|
||||
#define APP_COPYRIGHT "Copyright (C) 2016-2025 xmrig.com"
|
||||
#define APP_KIND "miner"
|
||||
|
||||
#define APP_VER_MAJOR 6
|
||||
#define APP_VER_MINOR 23
|
||||
#define APP_VER_PATCH 0
|
||||
#define APP_VER_MINOR 24
|
||||
#define APP_VER_PATCH 1
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# if (_MSC_VER >= 1930)
|
||||
# if (_MSC_VER >= 1950)
|
||||
# define MSVC_VERSION 2026
|
||||
# elif (_MSC_VER >=1930 && _MSC_VER < 1950)
|
||||
# define MSVC_VERSION 2022
|
||||
# elif (_MSC_VER >= 1920 && _MSC_VER < 1930)
|
||||
# define MSVC_VERSION 2019
|
||||
@@ -64,6 +66,10 @@
|
||||
# define APP_OS "Linux"
|
||||
#elif defined XMRIG_OS_FREEBSD
|
||||
# define APP_OS "FreeBSD"
|
||||
#elif defined XMRIG_OS_OPENBSD
|
||||
# define APP_OS "OpenBSD"
|
||||
#elif defined XMRIG_OS_HAIKU
|
||||
# define APP_OS "Haiku"
|
||||
#else
|
||||
# define APP_OS "Unknown OS"
|
||||
#endif
|
||||
@@ -73,6 +79,8 @@
|
||||
|
||||
#ifdef XMRIG_ARM
|
||||
# define APP_ARCH "ARMv" STR2(XMRIG_ARM)
|
||||
#elif defined(XMRIG_RISCV)
|
||||
# define APP_ARCH "RISC-V"
|
||||
#else
|
||||
# if defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || defined(_M_AMD64)
|
||||
# define APP_ARCH "x86-64"
|
||||
|
||||
Reference in New Issue
Block a user