1
0
mirror of https://github.com/xmrig/xmrig.git synced 2025-12-07 16:05:05 -05:00

Compare commits

...

24 Commits

Author SHA1 Message Date
XMRig
a44b21cef3 Cleanup 2025-10-27 19:18:52 +07:00
XMRig
ea832899f2 Fixed macOS build. 2025-10-23 11:17:59 +07:00
xmrig
3ecacf0ac2 Merge pull request #3725 from SChernykh/dev
RISC-V integration and JIT compiler
2025-10-23 11:02:21 +07:00
SChernykh
27c8e60919 Removed unused files 2025-10-22 23:31:02 +02:00
SChernykh
985fe06e8d RISC-V: test for instruction extensions 2025-10-22 19:21:26 +02:00
SChernykh
75b63ddde9 RISC-V JIT compiler 2025-10-22 19:00:20 +02:00
slayingripper
643b65f2c0 RISC-V Intergration 2025-10-22 18:57:20 +02:00
xmrig
116ba1828f Merge pull request #3722 from SChernykh/dev
Added Zen4 (Hawk Point) CPUs detection
2025-10-15 13:23:36 +07:00
SChernykh
da5a5674b4 Added Zen4 (Hawk Point) CPUs detection 2025-10-15 08:07:58 +02:00
xmrig
6cc4819cec Merge pull request #3719 from SChernykh/dev
Fix: correct FCMP++ version number
2025-10-05 18:28:21 +07:00
SChernykh
a659397c41 Fix: correct FCMP++ version number 2025-10-05 13:24:55 +02:00
xmrig
20acfd0d79 Merge pull request #3718 from SChernykh/dev
Solo mining: added support for FCMP++ hardfork
2025-10-05 18:04:23 +07:00
SChernykh
da683d8c3e Solo mining: added support for FCMP++ hardfork 2025-10-05 13:00:21 +02:00
XMRig
255565b533 Merge branch 'xtophyr-master' into dev 2025-09-22 21:31:28 +07:00
XMRig
878e83bf59 Merge branch 'master' of https://github.com/xtophyr/xmrig into xtophyr-master 2025-09-22 21:31:14 +07:00
Christopher Wright
7abf17cb59 adjust instruction/register suffixes to compile with gcc-based assemblers. 2025-09-21 14:57:42 -04:00
Christopher Wright
eeec5ecd10 undo this change 2025-09-20 08:38:40 -04:00
Christopher Wright
93f5067999 minor Aarch64 JIT changes (better instruction selection, don't emit instructions that add 0, etc) 2025-09-20 08:32:32 -04:00
XMRig
dd6671bc59 Merge branch 'dev' of github.com:xmrig/xmrig into dev 2025-06-29 12:29:01 +07:00
XMRig
a1ee2fd9d2 Improved LibreSSL support. 2025-06-29 12:28:35 +07:00
xmrig
2619131176 Merge pull request #3680 from benthetechguy/armhf
Add armv8l to list of 32 bit ARM targets
2025-06-25 04:14:22 +07:00
Ben Westover
1161f230c5 Add armv8l to list of 32 bit ARM targets
armv8l is what CMAKE_SYSTEM_PROCESSOR is set to when an ARMv8 processor
is in 32-bit mode, so it should be added to the ARMv7 target list even
though it's v8 because it's 32 bits. Currently, it's not in any ARM
target list which means x86 is assumed and the build fails.
2025-06-24 15:28:01 -04:00
XMRig
d2363ba28b v6.24.1-dev 2025-06-23 08:37:15 +07:00
XMRig
1676da1fe9 Merge branch 'master' into dev 2025-06-23 08:36:52 +07:00
46 changed files with 5573 additions and 155 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ scripts/deps
/CMakeLists.txt.user /CMakeLists.txt.user
/.idea /.idea
/src/backend/opencl/cl/cn/cryptonight_gen.cl /src/backend/opencl/cl/cn/cryptonight_gen.cl
.vscode

View File

@@ -95,7 +95,7 @@ set(HEADERS_CRYPTO
src/crypto/common/VirtualMemory.h 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) set(HEADERS_CRYPTO "${HEADERS_CRYPTO}" src/crypto/cn/CryptoNight_arm.h)
else() else()
set(HEADERS_CRYPTO "${HEADERS_CRYPTO}" src/crypto/cn/CryptoNight_x86.h) set(HEADERS_CRYPTO "${HEADERS_CRYPTO}" src/crypto/cn/CryptoNight_x86.h)

View File

@@ -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. 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 ## Mining backends
- **CPU** (x86/x64/ARMv7/ARMv8) - **CPU** (x86/x64/ARMv7/ARMv8/RISC-V)
- **OpenCL** for AMD GPUs. - **OpenCL** for AMD GPUs.
- **CUDA** for NVIDIA GPUs via external [CUDA plugin](https://github.com/xmrig/xmrig-cuda). - **CUDA** for NVIDIA GPUs via external [CUDA plugin](https://github.com/xmrig/xmrig-cuda).

View File

@@ -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") set(XMRIG_ASM_LIBRARY "xmrig-asm")
if (CMAKE_C_COMPILER_ID MATCHES MSVC) if (CMAKE_C_COMPILER_ID MATCHES MSVC)

View File

@@ -21,6 +21,19 @@ if (NOT VAES_SUPPORTED)
set(WITH_VAES OFF) set(WITH_VAES OFF)
endif() 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)$") if (XMRIG_64_BIT AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$")
add_definitions(-DRAPIDJSON_SSE2) add_definitions(-DRAPIDJSON_SSE2)
else() else()
@@ -29,6 +42,45 @@ else()
set(WITH_VAES OFF) set(WITH_VAES OFF)
endif() 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 add_definitions(-DRAPIDJSON_WRITE_DEFAULT_FLAGS=6) # rapidjson::kWriteNanAndInfFlag | rapidjson::kWriteNanAndInfNullFlag
if (ARM_V8) if (ARM_V8)
@@ -40,7 +92,7 @@ endif()
if (NOT ARM_TARGET) if (NOT ARM_TARGET)
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64|armv8-a)$") if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64|armv8-a)$")
set(ARM_TARGET 8) 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) set(ARM_TARGET 7)
endif() endif()
endif() endif()

View File

@@ -28,6 +28,11 @@ if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
elseif (ARM_TARGET EQUAL 7) elseif (ARM_TARGET EQUAL 7)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv7-a -mfpu=neon -flax-vector-conversions") 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") 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() else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
@@ -74,6 +79,11 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
elseif (ARM_TARGET EQUAL 7) elseif (ARM_TARGET EQUAL 7)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon -march=${CMAKE_SYSTEM_PROCESSOR}") 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}") 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() else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")

View File

@@ -17,6 +17,8 @@ else()
set(XMRIG_OS_LINUX ON) set(XMRIG_OS_LINUX ON)
elseif(CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR CMAKE_SYSTEM_NAME STREQUAL DragonFly) elseif(CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR CMAKE_SYSTEM_NAME STREQUAL DragonFly)
set(XMRIG_OS_FREEBSD ON) set(XMRIG_OS_FREEBSD ON)
elseif(CMAKE_SYSTEM_NAME STREQUAL OpenBSD)
set(XMRIG_OS_OPENBSD ON)
endif() endif()
endif() endif()
@@ -43,6 +45,8 @@ elseif(XMRIG_OS_UNIX)
add_definitions(-DXMRIG_OS_LINUX) add_definitions(-DXMRIG_OS_LINUX)
elseif (XMRIG_OS_FREEBSD) elseif (XMRIG_OS_FREEBSD)
add_definitions(-DXMRIG_OS_FREEBSD) add_definitions(-DXMRIG_OS_FREEBSD)
elseif (XMRIG_OS_OPENBSD)
add_definitions(-DXMRIG_OS_OPENBSD)
endif() endif()
endif() endif()

View File

@@ -62,7 +62,7 @@ if (WITH_RANDOMX)
src/crypto/randomx/jit_compiler_x86_static.asm src/crypto/randomx/jit_compiler_x86_static.asm
src/crypto/randomx/jit_compiler_x86.cpp 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 list(APPEND SOURCES_CRYPTO
src/crypto/randomx/jit_compiler_x86_static.S src/crypto/randomx/jit_compiler_x86_static.S
src/crypto/randomx/jit_compiler_x86.cpp src/crypto/randomx/jit_compiler_x86.cpp
@@ -80,6 +80,13 @@ if (WITH_RANDOMX)
else() else()
set_property(SOURCE src/crypto/randomx/jit_compiler_a64_static.S PROPERTY LANGUAGE C) set_property(SOURCE src/crypto/randomx/jit_compiler_a64_static.S PROPERTY LANGUAGE C)
endif() 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() else()
list(APPEND SOURCES_CRYPTO list(APPEND SOURCES_CRYPTO
src/crypto/randomx/jit_compiler_fallback.cpp src/crypto/randomx/jit_compiler_fallback.cpp
@@ -116,7 +123,7 @@ if (WITH_RANDOMX)
) )
endif() 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_FEATURE_MSR)
add_definitions(/DXMRIG_FIX_RYZEN) add_definitions(/DXMRIG_FIX_RYZEN)
message("-- WITH_MSR=ON") message("-- WITH_MSR=ON")

365
doc/RISCV_PERF_TUNING.md Normal file
View 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.

View File

@@ -12,7 +12,7 @@ if grep -E 'AMD Ryzen|AMD EPYC|AuthenticAMD' /proc/cpuinfo > /dev/null;
then then
if grep "cpu family[[:space:]]\{1,\}:[[:space:]]25" /proc/cpuinfo > /dev/null; if grep "cpu family[[:space:]]\{1,\}:[[:space:]]25" /proc/cpuinfo > /dev/null;
then 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 then
echo "Detected Zen4 CPU" echo "Detected Zen4 CPU"
wrmsr -a 0xc0011020 0x4400000000000 wrmsr -a 0xc0011020 0x4400000000000

View File

@@ -35,7 +35,7 @@ if (CMAKE_C_COMPILER_ID MATCHES MSVC)
add_feature_impl(xop "" HAVE_XOP) add_feature_impl(xop "" HAVE_XOP)
add_feature_impl(avx2 "/arch:AVX2" HAVE_AVX2) add_feature_impl(avx2 "/arch:AVX2" HAVE_AVX2)
add_feature_impl(avx512f "/arch:AVX512F" HAVE_AVX512F) 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) function(add_feature_impl FEATURE GCC_FLAG DEF)
add_library(argon2-${FEATURE} STATIC arch/x86_64/lib/argon2-${FEATURE}.c) add_library(argon2-${FEATURE} STATIC arch/x86_64/lib/argon2-${FEATURE}.c)
target_include_directories(argon2-${FEATURE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../) target_include_directories(argon2-${FEATURE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../)

View File

@@ -46,7 +46,12 @@ else()
set(CPUID_LIB "") set(CPUID_LIB "")
endif() 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) list(APPEND SOURCES_BACKEND_CPU src/backend/cpu/platform/BasicCpuInfo_arm.cpp)
if (XMRIG_OS_WIN) if (XMRIG_OS_WIN)

View File

@@ -91,7 +91,7 @@ public:
ICpuInfo() = default; ICpuInfo() = default;
virtual ~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; } inline constexpr static bool is64bit() { return true; }
# else # else
inline constexpr static bool is64bit() { return false; } inline constexpr static bool is64bit() { return false; }

View File

@@ -250,7 +250,7 @@ xmrig::BasicCpuInfo::BasicCpuInfo() :
break; break;
case 0x19: case 0x19:
if (m_model == 0x61) { if ((m_model == 0x61) || (m_model == 0x75)) {
m_arch = ARCH_ZEN4; m_arch = ARCH_ZEN4;
m_msrMod = MSR_MOD_RYZEN_19H_ZEN4; m_msrMod = MSR_MOD_RYZEN_19H_ZEN4;
} }

View File

@@ -65,7 +65,7 @@ protected:
inline Vendor vendor() const override { return m_vendor; } inline Vendor vendor() const override { return m_vendor; }
inline uint32_t model() const override inline uint32_t model() const override
{ {
# ifndef XMRIG_ARM # if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
return m_model; return m_model;
# else # else
return 0; return 0;
@@ -80,7 +80,7 @@ protected:
Vendor m_vendor = VENDOR_UNKNOWN; Vendor m_vendor = VENDOR_UNKNOWN;
private: private:
# ifndef XMRIG_ARM # if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
uint32_t m_procInfo = 0; uint32_t m_procInfo = 0;
uint32_t m_family = 0; uint32_t m_family = 0;
uint32_t m_model = 0; uint32_t m_model = 0;

View 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;
}

View File

@@ -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) static inline std::vector<hwloc_obj_t> findByType(hwloc_obj_t obj, hwloc_obj_type_t type)
{ {
std::vector<hwloc_obj_t> out; 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 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) { if (L2() == 0 && L3() == 0) {
return BasicCpuInfo::threads(algorithm, limit); 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 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; constexpr size_t oneMiB = 1024U * 1024U;
size_t PUs = countByType(cache, HWLOC_OBJ_PU); size_t PUs = countByType(cache, HWLOC_OBJ_PU);

View 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

View File

@@ -1,6 +1,6 @@
/* XMRig /* XMRig
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * Copyright (c) 2016-2025 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * 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 #ifndef XMRIG_FEATURE_HWLOC
#ifdef __DragonFly__ #if defined(__DragonFly__) || defined(XMRIG_OS_OPENBSD)
bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id) bool xmrig::Platform::setThreadAffinity(uint64_t cpu_id)
{ {
return true; return false;
} }
#else #else

View File

@@ -1,7 +1,7 @@
/* XMRig /* XMRig
* Copyright (c) 2018 Lee Clagett <https://github.com/vtnerd> * Copyright (c) 2018 Lee Clagett <https://github.com/vtnerd>
* Copyright (c) 2018-2023 SChernykh <https://github.com/SChernykh> * Copyright (c) 2018-2025 SChernykh <https://github.com/SChernykh>
* Copyright (c) 2016-2023 XMRig <https://github.com/xmrig>, <support@xmrig.com> * Copyright (c) 2016-2025 XMRig <https://github.com/xmrig>, <support@xmrig.com>
* *
* This program is free software: you can redistribute it and/or modify * 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 * 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 // 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 DH *get_dh2048()
{ {
static unsigned char dhp_2048[] = { 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_NO_SSLv2 | SSL_OP_NO_SSLv3);
SSL_CTX_set_options(m_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); 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); SSL_CTX_set_max_early_data(m_ctx, 0);
# endif # endif
@@ -180,7 +180,7 @@ bool xmrig::TlsContext::setCipherSuites(const char *ciphersuites)
return true; 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) { if (SSL_CTX_set_ciphersuites(m_ctx, ciphersuites) == 1) {
return true; return true;
} }
@@ -194,7 +194,7 @@ bool xmrig::TlsContext::setCipherSuites(const char *ciphersuites)
bool xmrig::TlsContext::setDH(const char *dhparam) 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; DH *dh = nullptr;
if (dhparam != nullptr) { if (dhparam != nullptr) {

View File

@@ -241,8 +241,13 @@ bool xmrig::BlockTemplate::parse(bool hashes)
ar(m_amount); ar(m_amount);
ar(m_outputType); ar(m_outputType);
// output type must be txout_to_key (2) or txout_to_tagged_key (3) const bool is_fcmp_pp = (m_coin == Coin::MONERO) && (m_version.first >= 17);
if ((m_outputType != 2) && (m_outputType != 3)) {
// 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; return false;
} }
@@ -250,6 +255,11 @@ bool xmrig::BlockTemplate::parse(bool hashes)
ar(m_ephPublicKey, kKeySize); ar(m_ephPublicKey, kKeySize);
if (is_fcmp_pp) {
ar(m_carrotViewTag);
ar(m_janusAnchor);
}
if (m_coin == Coin::ZEPHYR) { if (m_coin == Coin::ZEPHYR) {
if (m_outputType != 2) { if (m_outputType != 2) {
return false; return false;

View File

@@ -148,6 +148,8 @@ private:
Buffer m_hashes; Buffer m_hashes;
Buffer m_minerTxMerkleTreeBranch; Buffer m_minerTxMerkleTreeBranch;
uint8_t m_rootHash[kHashSize]{}; uint8_t m_rootHash[kHashSize]{};
uint8_t m_carrotViewTag[3]{};
uint8_t m_janusAnchor[16]{};
}; };

View File

@@ -23,7 +23,7 @@
#include "crypto/common/VirtualMemory.h" #include "crypto/common/VirtualMemory.h"
#if defined(XMRIG_ARM) #if defined(XMRIG_ARM) || defined(XMRIG_RISCV)
# include "crypto/cn/CryptoNight_arm.h" # include "crypto/cn/CryptoNight_arm.h"
#else #else
# include "crypto/cn/CryptoNight_x86.h" # include "crypto/cn/CryptoNight_x86.h"

View File

@@ -30,7 +30,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#if defined _MSC_VER || defined XMRIG_ARM #if defined _MSC_VER || defined XMRIG_ARM || defined XMRIG_RISCV
# define ABI_ATTRIBUTE # define ABI_ATTRIBUTE
#else #else
# define ABI_ATTRIBUTE __attribute__((ms_abi)) # define ABI_ATTRIBUTE __attribute__((ms_abi))

View File

@@ -27,6 +27,9 @@
#ifndef XMRIG_CRYPTONIGHT_ARM_H #ifndef XMRIG_CRYPTONIGHT_ARM_H
#define XMRIG_CRYPTONIGHT_ARM_H #define XMRIG_CRYPTONIGHT_ARM_H
#ifdef XMRIG_RISCV
# include "crypto/cn/sse2rvv.h"
#endif
#include "base/crypto/keccak.h" #include "base/crypto/keccak.h"
#include "crypto/cn/CnAlgo.h" #include "crypto/cn/CnAlgo.h"

View File

@@ -30,7 +30,7 @@
#include <math.h> #include <math.h>
// VARIANT ALTERATIONS // VARIANT ALTERATIONS
#ifndef XMRIG_ARM #if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
# define VARIANT1_INIT(part) \ # define VARIANT1_INIT(part) \
uint64_t tweak1_2_##part = 0; \ uint64_t tweak1_2_##part = 0; \
if (BASE == Algorithm::CN_1) { \ if (BASE == Algorithm::CN_1) { \
@@ -60,7 +60,7 @@
} }
#ifndef XMRIG_ARM #if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
# define VARIANT2_INIT(part) \ # define VARIANT2_INIT(part) \
__m128i division_result_xmm_##part = _mm_cvtsi64_si128(static_cast<int64_t>(h##part[12])); \ __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])); __m128i sqrt_result_xmm_##part = _mm_cvtsi64_si128(static_cast<int64_t>(h##part[13]));

View File

@@ -29,6 +29,8 @@
#if defined(XMRIG_ARM) #if defined(XMRIG_ARM)
# include "crypto/cn/sse2neon.h" # include "crypto/cn/sse2neon.h"
#elif defined(XMRIG_RISCV)
# include "crypto/cn/sse2rvv.h"
#elif defined(__GNUC__) #elif defined(__GNUC__)
# include <x86intrin.h> # include <x86intrin.h>
#else #else

748
src/crypto/cn/sse2rvv.h Normal file
View 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 */

View 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 */

View 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 */

View File

@@ -26,7 +26,7 @@
#define XMRIG_MM_MALLOC_PORTABLE_H #define XMRIG_MM_MALLOC_PORTABLE_H
#if defined(XMRIG_ARM) && !defined(__clang__) #if (defined(XMRIG_ARM) || defined(XMRIG_RISCV)) && !defined(__clang__)
#include <stdlib.h> #include <stdlib.h>

View File

@@ -57,6 +57,9 @@
#if defined(XMRIG_ARM) #if defined(XMRIG_ARM)
# include "crypto/cn/sse2neon.h" # 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__) #elif defined(__GNUC__)
# include <x86intrin.h> # include <x86intrin.h>
#else #else
@@ -286,7 +289,7 @@ struct HelperThread
void benchmark() void benchmark()
{ {
#ifndef XMRIG_ARM #if !defined(XMRIG_ARM) && !defined(XMRIG_RISCV)
static std::atomic<int> done{ 0 }; static std::atomic<int> done{ 0 };
if (done.exchange(1)) { if (done.exchange(1)) {
return; 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) 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 helper_cpu_set = hwloc_bitmap_alloc();
hwloc_bitmap_t main_threads_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]; uint32_t cn_indices[6];
select_indices(cn_indices, seed); 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 }; uint32_t step[6] = { 1, 1, 1, 1, 1, 1 };
#else #else
uint32_t step[6] = { 4, 4, 1, 2, 4, 4 }; uint32_t step[6] = { 4, 4, 1, 2, 4, 4 };

View File

@@ -111,6 +111,10 @@ namespace randomx {
#define RANDOMX_HAVE_COMPILER 1 #define RANDOMX_HAVE_COMPILER 1
class JitCompilerA64; class JitCompilerA64;
using JitCompiler = JitCompilerA64; using JitCompiler = JitCompilerA64;
#elif defined(__riscv) && defined(__riscv_xlen) && (__riscv_xlen == 64)
#define RANDOMX_HAVE_COMPILER 1
class JitCompilerRV64;
using JitCompiler = JitCompilerRV64;
#else #else
#define RANDOMX_HAVE_COMPILER 0 #define RANDOMX_HAVE_COMPILER 0
class JitCompilerFallback; class JitCompilerFallback;

View File

@@ -32,6 +32,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "crypto/randomx/jit_compiler_x86.hpp" #include "crypto/randomx/jit_compiler_x86.hpp"
#elif defined(__aarch64__) #elif defined(__aarch64__)
#include "crypto/randomx/jit_compiler_a64.hpp" #include "crypto/randomx/jit_compiler_a64.hpp"
#elif defined(__riscv) && defined(__riscv_xlen) && (__riscv_xlen == 64)
#include "crypto/randomx/jit_compiler_rv64.hpp"
#else #else
#include "crypto/randomx/jit_compiler_fallback.hpp" #include "crypto/randomx/jit_compiler_fallback.hpp"
#endif #endif

View File

@@ -67,7 +67,6 @@ constexpr uint32_t LDR_LITERAL = 0x58000000;
constexpr uint32_t ROR = 0x9AC02C00; constexpr uint32_t ROR = 0x9AC02C00;
constexpr uint32_t ROR_IMM = 0x93C00000; constexpr uint32_t ROR_IMM = 0x93C00000;
constexpr uint32_t MOV_REG = 0xAA0003E0; constexpr uint32_t MOV_REG = 0xAA0003E0;
constexpr uint32_t MOV_VREG_EL = 0x6E080400;
constexpr uint32_t FADD = 0x4E60D400; constexpr uint32_t FADD = 0x4E60D400;
constexpr uint32_t FSUB = 0x4EE0D400; constexpr uint32_t FSUB = 0x4EE0D400;
constexpr uint32_t FEOR = 0x6E201C00; 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); ((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) : JitCompilerA64::JitCompilerA64(bool hugePagesEnable, bool) :
hugePages(hugePagesJIT && hugePagesEnable), hugePages(hugePagesJIT && hugePagesEnable),
@@ -128,11 +127,12 @@ void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& con
uint32_t codePos = MainLoopBegin + 4; uint32_t codePos = MainLoopBegin + 4;
uint32_t mask = ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 7) << 10);
// and w16, w10, ScratchpadL3Mask64 // 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 // 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; codePos = PrologueSize;
literalPos = ImulRcpLiteralsEnd; 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; 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); 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)); 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 // and w10, w10, CacheLineAlignMask
codePos = (((uint8_t*)randomx_program_aarch64_cacheline_align_mask2) - ((uint8_t*)randomx_program_aarch64)); 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 // Update spMix1
// eor x10, config.readReg0, config.readReg1 // eor x10, config.readReg0, config.readReg1
@@ -497,9 +498,12 @@ void JitCompilerA64::emitMemLoad(uint32_t dst, uint32_t src, Instruction& instr,
if (src != dst) if (src != dst)
{ {
imm &= instr.getModMem() ? (RandomX_CurrentConfig.ScratchpadL1_Size - 1) : (RandomX_CurrentConfig.ScratchpadL2_Size - 1); imm &= instr.getModMem() ? (RandomX_CurrentConfig.ScratchpadL1_Size - 1) : (RandomX_CurrentConfig.ScratchpadL2_Size - 1);
uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
if (imm)
emitAddImmediate(tmp_reg, src, imm, code, k); 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 andInstrL1 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL1 - 4) << 10);
const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10); const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10);
@@ -511,11 +515,19 @@ void JitCompilerA64::emitMemLoad(uint32_t dst, uint32_t src, Instruction& instr,
else else
{ {
imm = (imm & ScratchpadL3Mask) >> 3; imm = (imm & ScratchpadL3Mask) >> 3;
if (imm)
{
emitMovImmediate(tmp_reg, imm, code, k); emitMovImmediate(tmp_reg, imm, code, k);
// ldr tmp_reg, [x2, tmp_reg, lsl 3] // ldr tmp_reg, [x2, tmp_reg, lsl 3]
emit32(0xf8607840 | tmp_reg | (tmp_reg << 16), code, k); emit32(0xf8607840 | tmp_reg | (tmp_reg << 16), code, k);
} }
else
{
// ldr tmp_reg, [x2]
emit32(0xf9400040 | tmp_reg, code, k);
}
}
codePos = k; codePos = k;
} }
@@ -529,25 +541,22 @@ void JitCompilerA64::emitMemLoadFP(uint32_t src, Instruction& instr, uint8_t* co
constexpr uint32_t tmp_reg = 19; constexpr uint32_t tmp_reg = 19;
imm &= instr.getModMem() ? (RandomX_CurrentConfig.ScratchpadL1_Size - 1) : (RandomX_CurrentConfig.ScratchpadL2_Size - 1); imm &= instr.getModMem() ? (RandomX_CurrentConfig.ScratchpadL1_Size - 1) : (RandomX_CurrentConfig.ScratchpadL2_Size - 1);
uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
if (imm)
emitAddImmediate(tmp_reg, src, imm, code, k); 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 andInstrL1 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL1 - 4) << 10);
const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10); const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10);
emit32(instr.getModMem() ? andInstrL1 : andInstrL2, code, k); emit32(instr.getModMem() ? andInstrL1 : andInstrL2, code, k);
// add tmp_reg, x2, tmp_reg // ldr tmp_reg_fp, [x2, tmp_reg]
emit32(ARMV8A::ADD | tmp_reg | (2 << 5) | (tmp_reg << 16), code, k); emit32(0x3ce06800 | tmp_reg_fp | (2 << 5) | (tmp_reg << 16), code, k);
// ldpsw tmp_reg, tmp_reg + 1, [tmp_reg] // sxtl.2d tmp_reg_fp, tmp_reg_fp
emit32(0x69400000 | tmp_reg | (tmp_reg << 5) | ((tmp_reg + 1) << 10), code, k); emit32(0x0f20a400 | tmp_reg_fp | (tmp_reg_fp << 5), 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);
// scvtf tmp_reg_fp.2d, tmp_reg_fp.2d // scvtf tmp_reg_fp.2d, tmp_reg_fp.2d
emit32(0x4E61D800 | tmp_reg_fp | (tmp_reg_fp << 5), code, k); emit32(0x4E61D800 | tmp_reg_fp | (tmp_reg_fp << 5), code, k);
@@ -835,6 +844,7 @@ void JitCompilerA64::h_IROR_R(Instruction& instr, uint32_t& codePos)
else else
{ {
// ror dst, dst, imm // ror dst, dst, imm
if ((instr.getImm32() & 63))
emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((instr.getImm32() & 63) << 10) | (dst << 16), code, codePos); emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((instr.getImm32() & 63) << 10) | (dst << 16), code, codePos);
} }
@@ -861,6 +871,7 @@ void JitCompilerA64::h_IROL_R(Instruction& instr, uint32_t& codePos)
else else
{ {
// ror dst, dst, imm // ror dst, dst, imm
if ((instr.getImm32() & 63))
emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((-instr.getImm32() & 63) << 10) | (dst << 16), code, k); emit32(ARMV8A::ROR_IMM | dst | (dst << 5) | ((-instr.getImm32() & 63) << 10) | (dst << 16), code, k);
} }
@@ -894,13 +905,8 @@ void JitCompilerA64::h_FSWAP_R(Instruction& instr, uint32_t& codePos)
const uint32_t dst = instr.dst + 16; const uint32_t dst = instr.dst + 16;
constexpr uint32_t tmp_reg_fp = 28; // ext dst.16b, dst.16b, dst.16b, #0x8
constexpr uint32_t src_index1 = 1 << 14; emit32(0x6e004000 | dst | (dst << 5) | (dst << 16), code, k);
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);
codePos = 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 tmp_reg = 20;
constexpr uint32_t fpcr_tmp_reg = 8; constexpr uint32_t fpcr_tmp_reg = 8;
if (instr.getImm32() & 63)
{
// ror tmp_reg, src, imm // ror tmp_reg, src, imm
emit32(ARMV8A::ROR_IMM | tmp_reg | (src << 5) | ((instr.getImm32() & 63) << 10) | (src << 16), code, k); emit32(ARMV8A::ROR_IMM | tmp_reg | (src << 5) | ((instr.getImm32() & 63) << 10) | (src << 16), code, k);
// bfi fpcr_tmp_reg, tmp_reg, 40, 2 // bfi fpcr_tmp_reg, tmp_reg, 40, 2
emit32(0xB3580400 | fpcr_tmp_reg | (tmp_reg << 5), code, k); 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 // rbit tmp_reg, fpcr_tmp_reg
emit32(0xDAC00000 | tmp_reg | (fpcr_tmp_reg << 5), code, k); emit32(0xDAC00000 | tmp_reg | (fpcr_tmp_reg << 5), code, k);
@@ -1059,9 +1073,12 @@ void JitCompilerA64::h_ISTORE(Instruction& instr, uint32_t& codePos)
else else
imm &= RandomX_CurrentConfig.ScratchpadL3_Size - 1; imm &= RandomX_CurrentConfig.ScratchpadL3_Size - 1;
uint32_t t = 0x927d0000 | tmp_reg | (tmp_reg << 5);
if (imm)
emitAddImmediate(tmp_reg, dst, imm, code, k); 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 andInstrL1 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL1 - 4) << 10);
const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10); const uint32_t andInstrL2 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL2 - 4) << 10);
const uint32_t andInstrL3 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 4) << 10); const uint32_t andInstrL3 = t | ((RandomX_CurrentConfig.Log2_ScratchpadL3 - 4) << 10);

View File

@@ -100,9 +100,9 @@
# v26 -> "a2" # v26 -> "a2"
# v27 -> "a3" # v27 -> "a3"
# v28 -> temporary # v28 -> temporary
# v29 -> E 'and' mask = 0x00ffffffffffffff00ffffffffffffff # v29 -> E 'and' mask = 0x00ffffffffffffff'00ffffffffffffff
# v30 -> E 'or' mask = 0x3*00000000******3*00000000****** # v30 -> E 'or' mask = 0x3*00000000******'3*00000000******
# v31 -> scale mask = 0x81f000000000000081f0000000000000 # v31 -> scale mask = 0x80f0000000000000'80f0000000000000
.balign 4 .balign 4
DECL(randomx_program_aarch64): DECL(randomx_program_aarch64):
@@ -142,17 +142,14 @@ DECL(randomx_program_aarch64):
ldp q26, q27, [x0, 224] ldp q26, q27, [x0, 224]
# Load E 'and' mask # Load E 'and' mask
mov x16, 0x00FFFFFFFFFFFFFF movi v29.2d, #0x00FFFFFFFFFFFFFF
ins v29.d[0], x16
ins v29.d[1], x16
# Load E 'or' mask (stored in reg.f[0]) # Load E 'or' mask (stored in reg.f[0])
ldr q30, [x0, 64] ldr q30, [x0, 64]
# Load scale mask # Load scale mask
mov x16, 0x80f0000000000000 mov x16, 0x80f0000000000000
ins v31.d[0], x16 dup v31.2d, x16
ins v31.d[1], x16
# Read fpcr # Read fpcr
mrs x8, fpcr mrs x8, fpcr
@@ -162,35 +159,22 @@ DECL(randomx_program_aarch64):
str x0, [sp, -16]! str x0, [sp, -16]!
# Read literals # Read literals
ldr x0, literal_x0 adr x30, literal_v0
ldr x11, literal_x11 ldp q0, q1, [x30]
ldr x21, literal_x21 ldp q2, q3, [x30, 32]
ldr x22, literal_x22 ldp q4, q5, [x30, 64]
ldr x23, literal_x23 ldp q6, q7, [x30, 96]
ldr x24, literal_x24 ldp q8, q9, [x30, 128]
ldr x25, literal_x25 ldp q10, q11, [x30, 160]
ldr x26, literal_x26 ldp q12, q13, [x30, 192]
ldr x27, literal_x27 ldp q14, q15, [x30, 224]
ldr x28, literal_x28
ldr x29, literal_x29
ldr x30, literal_x30
ldr q0, literal_v0 ldp x0, x11, [x30, -96] // literal_x0
ldr q1, literal_v1 ldp x21, x22, [x30, -80] // literal_x21
ldr q2, literal_v2 ldp x23, x24, [x30, -64] // literal_x23
ldr q3, literal_v3 ldp x25, x26, [x30, -48] // literal_x25
ldr q4, literal_v4 ldp x27, x28, [x30, -32] // literal_x27
ldr q5, literal_v5 ldp x29, x30, [x30, -16] // literal_x29
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
DECL(randomx_program_aarch64_main_loop): DECL(randomx_program_aarch64_main_loop):
# spAddr0 = spMix1 & ScratchpadL3Mask64; # spAddr0 = spMix1 & ScratchpadL3Mask64;
@@ -221,40 +205,31 @@ DECL(randomx_program_aarch64_main_loop):
eor x15, x15, x19 eor x15, x15, x19
# Load group F registers (spAddr1) # Load group F registers (spAddr1)
ldpsw x20, x19, [x17] ldr q17, [x17]
ins v16.d[0], x20 sxtl v16.2d, v17.2s
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
scvtf v16.2d, v16.2d scvtf v16.2d, v16.2d
sxtl2 v17.2d, v17.4s
scvtf v17.2d, v17.2d scvtf v17.2d, v17.2d
ldr q19, [x17, 16]
sxtl v18.2d, v19.2s
scvtf v18.2d, v18.2d scvtf v18.2d, v18.2d
sxtl2 v19.2d, v19.4s
scvtf v19.2d, v19.2d scvtf v19.2d, v19.2d
# Load group E registers (spAddr1) # Load group E registers (spAddr1)
ldpsw x20, x19, [x17, 32] ldr q21, [x17, 32]
ins v20.d[0], x20 sxtl v20.2d, v21.2s
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
scvtf v20.2d, v20.2d scvtf v20.2d, v20.2d
sxtl2 v21.2d, v21.4s
scvtf v21.2d, v21.2d scvtf v21.2d, v21.2d
ldr q23, [x17, 48]
sxtl v22.2d, v23.2s
scvtf v22.2d, v22.2d scvtf v22.2d, v22.2d
sxtl2 v23.2d, v23.4s
scvtf v23.2d, v23.2d scvtf v23.2d, v23.2d
and v20.16b, v20.16b, v29.16b and v20.16b, v20.16b, v29.16b
and v21.16b, v21.16b, v29.16b and v21.16b, v21.16b, v29.16b
and v22.16b, v22.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 eor x9, x9, x20
# Calculate dataset pointer for dataset prefetch # Calculate dataset pointer for dataset prefetch
mov w20, w9
DECL(randomx_program_aarch64_cacheline_align_mask1): DECL(randomx_program_aarch64_cacheline_align_mask1):
# Actual mask will be inserted by JIT compiler # Actual mask will be inserted by JIT compiler
and x20, x20, 1 and x20, x9, 1
add x20, x20, x1 add x20, x20, x1
# Prefetch dataset data # Prefetch dataset data
@@ -491,42 +465,39 @@ DECL(randomx_calc_dataset_item_aarch64):
stp x10, x11, [sp, 80] stp x10, x11, [sp, 80]
stp x12, x13, [sp, 96] stp x12, x13, [sp, 96]
ldr x12, superscalarMul0 adr x7, superscalarMul0
# superscalarMul0, superscalarAdd1
ldp x12, x13, [x7]
mov x8, x0 ldp x8, x9, [sp]
mov x9, x1
mov x10, x2 mov x10, x2
# rl[0] = (itemNumber + 1) * superscalarMul0; # rl[0] = (itemNumber + 1) * superscalarMul0;
madd x0, x2, x12, x12 madd x0, x2, x12, x12
# rl[1] = rl[0] ^ superscalarAdd1; # rl[1] = rl[0] ^ superscalarAdd1;
ldr x12, superscalarAdd1 eor x1, x0, x13
eor x1, x0, x12
# rl[2] = rl[0] ^ superscalarAdd2; # rl[2] = rl[0] ^ superscalarAdd2;
ldr x12, superscalarAdd2 ldp x12, x13, [x7, 16]
eor x2, x0, x12 eor x2, x0, x12
# rl[3] = rl[0] ^ superscalarAdd3; # rl[3] = rl[0] ^ superscalarAdd3;
ldr x12, superscalarAdd3 eor x3, x0, x13
eor x3, x0, x12
# rl[4] = rl[0] ^ superscalarAdd4; # rl[4] = rl[0] ^ superscalarAdd4;
ldr x12, superscalarAdd4 ldp x12, x13, [x7, 32]
eor x4, x0, x12 eor x4, x0, x12
# rl[5] = rl[0] ^ superscalarAdd5; # rl[5] = rl[0] ^ superscalarAdd5;
ldr x12, superscalarAdd5 eor x5, x0, x13
eor x5, x0, x12
# rl[6] = rl[0] ^ superscalarAdd6; # rl[6] = rl[0] ^ superscalarAdd6;
ldr x12, superscalarAdd6 ldp x12, x13, [x7, 48]
eor x6, x0, x12 eor x6, x0, x12
# rl[7] = rl[0] ^ superscalarAdd7; # rl[7] = rl[0] ^ superscalarAdd7;
ldr x12, superscalarAdd7 eor x7, x0, x13
eor x7, x0, x12
b DECL(randomx_calc_dataset_item_aarch64_prefetch) b DECL(randomx_calc_dataset_item_aarch64_prefetch)

File diff suppressed because it is too large Load Diff

View 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);
};
}

File diff suppressed because it is too large Load Diff

View 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();
}

View File

@@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "crypto/randomx/jit_compiler_x86_static.hpp" #include "crypto/randomx/jit_compiler_x86_static.hpp"
#elif (XMRIG_ARM == 8) #elif (XMRIG_ARM == 8)
#include "crypto/randomx/jit_compiler_a64_static.hpp" #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 #endif
#include "backend/cpu/Cpu.h" #include "backend/cpu/Cpu.h"
@@ -190,7 +192,7 @@ RandomX_ConfigurationBase::RandomX_ConfigurationBase()
# endif # 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; } static uint32_t Log2(size_t value) { return (value > 1) ? (Log2(value / 2) + 1) : 0; }
#endif #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 #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 #else
#define JIT_HANDLE(x, prev) #define JIT_HANDLE(x, prev)
#endif #endif

View File

@@ -133,7 +133,7 @@ struct RandomX_ConfigurationBase
uint32_t ScratchpadL3Mask_Calculated; uint32_t ScratchpadL3Mask_Calculated;
uint32_t ScratchpadL3Mask64_Calculated; uint32_t ScratchpadL3Mask64_Calculated;
# if (XMRIG_ARM == 8) # if (XMRIG_ARM == 8) || defined(XMRIG_RISCV)
uint32_t Log2_ScratchpadL1; uint32_t Log2_ScratchpadL1;
uint32_t Log2_ScratchpadL2; uint32_t Log2_ScratchpadL2;
uint32_t Log2_ScratchpadL3; uint32_t Log2_ScratchpadL3;

View 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

View 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

View File

@@ -29,9 +29,17 @@ randomx_vm *xmrig::RxVm::create(RxDataset *dataset, uint8_t *scratchpad, bool so
{ {
int flags = 0; 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) { if (!softAes) {
flags |= RANDOMX_FLAG_HARD_AES; flags |= RANDOMX_FLAG_HARD_AES;
} }
# else
(void)softAes; // unused on RISC-V to force soft AES
# endif
if (dataset->get()) { if (dataset->get()) {
flags |= RANDOMX_FLAG_FULL_MEM; flags |= RANDOMX_FLAG_FULL_MEM;

View File

@@ -22,7 +22,7 @@
#define APP_ID "xmrig" #define APP_ID "xmrig"
#define APP_NAME "XMRig" #define APP_NAME "XMRig"
#define APP_DESC "XMRig miner" #define APP_DESC "XMRig miner"
#define APP_VERSION "6.24.0" #define APP_VERSION "6.24.1-dev"
#define APP_DOMAIN "xmrig.com" #define APP_DOMAIN "xmrig.com"
#define APP_SITE "www.xmrig.com" #define APP_SITE "www.xmrig.com"
#define APP_COPYRIGHT "Copyright (C) 2016-2025 xmrig.com" #define APP_COPYRIGHT "Copyright (C) 2016-2025 xmrig.com"
@@ -30,7 +30,7 @@
#define APP_VER_MAJOR 6 #define APP_VER_MAJOR 6
#define APP_VER_MINOR 24 #define APP_VER_MINOR 24
#define APP_VER_PATCH 0 #define APP_VER_PATCH 1
#ifdef _MSC_VER #ifdef _MSC_VER
# if (_MSC_VER >= 1930) # if (_MSC_VER >= 1930)
@@ -64,6 +64,8 @@
# define APP_OS "Linux" # define APP_OS "Linux"
#elif defined XMRIG_OS_FREEBSD #elif defined XMRIG_OS_FREEBSD
# define APP_OS "FreeBSD" # define APP_OS "FreeBSD"
#elif defined XMRIG_OS_OPENBSD
# define APP_OS "OpenBSD"
#else #else
# define APP_OS "Unknown OS" # define APP_OS "Unknown OS"
#endif #endif
@@ -73,6 +75,8 @@
#ifdef XMRIG_ARM #ifdef XMRIG_ARM
# define APP_ARCH "ARMv" STR2(XMRIG_ARM) # define APP_ARCH "ARMv" STR2(XMRIG_ARM)
#elif defined(XMRIG_RISCV)
# define APP_ARCH "RISC-V"
#else #else
# if defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || defined(_M_AMD64) # if defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || defined(_M_AMD64)
# define APP_ARCH "x86-64" # define APP_ARCH "x86-64"