diff --git a/.drone.yml b/.drone.yml index 1c94efc..997bb7d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,7 +1,7 @@ --- kind: pipeline type: docker -name: from-source-amd64 +name: go-amd64-asm-jit platform: os: linux arch: amd64 @@ -28,7 +28,61 @@ steps: --- kind: pipeline type: docker -name: from-source-386 +name: go-amd64-asm +platform: + os: linux + arch: amd64 + +environment: + GOPROXY: direct + GOARCH: amd64 + GOAMD64: v3 + GOOS: linux + GOTRACEBACK: 2 + GOEXPERIMENT: "cgocheck2,newinliner" + CGO_ENABLED: "0" + +workspace: + path: /drone/src + +steps: + - name: test + image: golang:1.22-alpine3.19 + commands: + - apk update + - apk add --no-cache git + - go test -tags disable_jit -p 1 -failfast -timeout 20m -cover -gcflags=-d=checkptr -v . +--- +kind: pipeline +type: docker +name: go-amd64-purego +platform: + os: linux + arch: amd64 + +environment: + GOPROXY: direct + GOARCH: amd64 + GOAMD64: v3 + GOOS: linux + GOTRACEBACK: 2 + GOEXPERIMENT: "cgocheck2,newinliner" + CGO_ENABLED: "0" + +workspace: + path: /drone/src + +steps: + - name: test + image: golang:1.22-alpine3.19 + commands: + - apk update + - apk add --no-cache git + - go test -tags purego -p 1 -failfast -timeout 20m -cover -gcflags=-d=checkptr -v . +--- +kind: pipeline +type: docker +name: go-386-asm platform: os: linux arch: amd64 @@ -55,7 +109,34 @@ steps: --- kind: pipeline type: docker -name: from-source-arm64 +name: go-386-purego +platform: + os: linux + arch: amd64 + +environment: + GOPROXY: direct + GOARCH: 386 + GO386: sse2 + GOOS: linux + GOTRACEBACK: 2 + GOEXPERIMENT: "cgocheck2,newinliner" + CGO_ENABLED: "0" + +workspace: + path: /drone/src + +steps: + - name: test + image: golang:1.22-alpine3.19 + commands: + - apk update + - apk add --no-cache git + - go test -tags purego -p 1 -failfast -timeout 20m -cover -gcflags=-d=checkptr -v . +--- +kind: pipeline +type: docker +name: go-arm64-asm platform: os: linux arch: arm64 @@ -78,4 +159,30 @@ steps: - apk update - apk add --no-cache git - go test -p 1 -failfast -timeout 20m -cover -gcflags=-d=checkptr -v . +--- +kind: pipeline +type: docker +name: go-arm64-purego +platform: + os: linux + arch: arm64 + +environment: + GOPROXY: direct + GOARCH: arm64 + GOOS: linux + GOTRACEBACK: 2 + GOEXPERIMENT: "cgocheck2,newinliner" + CGO_ENABLED: "0" + +workspace: + path: /drone/src + +steps: + - name: test + image: golang:1.22-alpine3.19 + commands: + - apk update + - apk add --no-cache git + - go test -tags purego -p 1 -failfast -timeout 20m -cover -gcflags=-d=checkptr -v . ... \ No newline at end of file diff --git a/README.md b/README.md index 8c292f4..884dd3f 100644 --- a/README.md +++ b/README.md @@ -4,21 +4,25 @@ Fork from [git.dero.io/DERO_Foundation/RandomX](https://git.dero.io/DERO_Foundat Original code failed RandomX testcases and was implemented using big.Float. -This package implements RandomX without CGO, using only Golang code, pure float64 ops and two small assembly sections to implement CFROUND modes. +This package implements RandomX without CGO, using only Golang code, pure float64 ops and two small assembly sections to implement CFROUND modes, with optional soft float implementation. All test cases pass properly. -Uses minimal Go assembly due to having to set rounding mode natively. Support can be added with supporting rounding mode under _asm_. +Uses minimal Go assembly due to having to set rounding mode natively. Native hard float can be added with supporting rounding mode under _asm_. JIT is supported on a few platforms but can be hard-disabled via the `disable_jit` build flag, or at runtime. -| Platform | Supported | SuperScalar JIT | Notes | -|:-----------:|:---------:|:---------------:|:----------------:| -| **386** | ✅ | ❌ | | -| **amd64** | ✅ | ✅* | JIT only on Unix | -| **arm** | ❌ | - | | -| **arm64** | ✅ | ❌ | | -| **mips** | ❌ | - | | -| **mips64** | ❌ | - | | -| **riscv64** | ❌ | - | | -| **wasm** | ❌ | - | | +A pure Golang implementation can be used on platforms without hard float support or via the `purego` build flag manually. + +| Platform | Supported | Hard Float | SuperScalar JIT | Notes | +|:-----------:|:---------:|:----------:|:---------------:|:----------------:| +| **386** | ✅ | ✅ | ❌ | | +| **amd64** | ✅ | ✅ | ✅* | JIT only on Unix | +| **arm** | ✅* | ❌ | ❌ | | +| **arm64** | ✅ | ✅ | ❌ | | +| **mips** | ✅* | ❌ | ❌ | | +| **mips64** | ✅* | ❌ | ❌ | | +| **riscv64** | ✅* | ❌ | ❌ | | +| **wasm** | ✅* | ❌ | ❌ | | + +* these platforms only support software floating point / purego and will not be performant. \ No newline at end of file diff --git a/asm/round.go b/asm/round.go index cc9acbc..e1d069e 100644 --- a/asm/round.go +++ b/asm/round.go @@ -1,7 +1,5 @@ package asm -import "git.gammaspectra.live/P2Pool/go-randomx/v2/softfloat" - -func SetRoundingMode(mode softfloat.RoundingMode) { +func SetRoundingMode[T ~uint64 | ~uint8](mode T) { setRoundingMode(uint8(mode)) } diff --git a/asm/round_386.go b/asm/round_386.go index a63ceb1..ae753fc 100644 --- a/asm/round_386.go +++ b/asm/round_386.go @@ -1,4 +1,4 @@ -//go:build 386 +//go:build 386 && !purego package asm diff --git a/asm/round_386.s b/asm/round_386.s index 64cf24c..33c9b61 100644 --- a/asm/round_386.s +++ b/asm/round_386.s @@ -1,3 +1,5 @@ +//go:build 386 && !purego + #include "textflag.h" // stmxcsr reads the MXCSR control and status register. diff --git a/asm/round_amd64.go b/asm/round_amd64.go index 6bfaf56..0816ed1 100644 --- a/asm/round_amd64.go +++ b/asm/round_amd64.go @@ -1,4 +1,4 @@ -//go:build amd64 +//go:build amd64 && !purego package asm diff --git a/asm/round_amd64.s b/asm/round_amd64.s index faff1bf..835856a 100644 --- a/asm/round_amd64.s +++ b/asm/round_amd64.s @@ -1,3 +1,5 @@ +//go:build amd64 && !purego + #include "textflag.h" // stmxcsr reads the MXCSR control and status register. diff --git a/asm/round_arm64.go b/asm/round_arm64.go index 2bf3e6b..254df4c 100644 --- a/asm/round_arm64.go +++ b/asm/round_arm64.go @@ -1,4 +1,4 @@ -//go:build arm64 +//go:build arm64 && !purego package asm diff --git a/asm/round_arm64.s b/asm/round_arm64.s index d637c26..2f276c6 100644 --- a/asm/round_arm64.s +++ b/asm/round_arm64.s @@ -1,3 +1,5 @@ +//go:build arm64 && !purego + #include "textflag.h" TEXT ·getFPCR(SB),NOSPLIT,$0-8 diff --git a/asm/round_noasm.go b/asm/round_noasm.go index 2d082c0..e259c7d 100644 --- a/asm/round_noasm.go +++ b/asm/round_noasm.go @@ -1,4 +1,4 @@ -//go:build !arm64 && !amd64 && !386 +//go:build (!arm64 && !amd64 && !386) || purego package asm diff --git a/exec_generic.go b/exec_generic.go index e2cd914..1b6cb22 100644 --- a/exec_generic.go +++ b/exec_generic.go @@ -1,4 +1,4 @@ -//go:build !unix || disable_jit +//go:build !unix || disable_jit || purego package randomx @@ -7,5 +7,5 @@ func (f ProgramFunc) Execute(rl *RegisterLine) { } func (f ProgramFunc) Close() error { - + return nil } diff --git a/exec_mmap_unix.go b/exec_mmap_unix.go index 2e05c24..bc84b5b 100644 --- a/exec_mmap_unix.go +++ b/exec_mmap_unix.go @@ -1,4 +1,4 @@ -//go:build unix && !disable_jit +//go:build unix && !disable_jit && !purego package randomx diff --git a/softfloat/funcs.go b/float.go similarity index 69% rename from softfloat/funcs.go rename to float.go index b9ff822..7724404 100644 --- a/softfloat/funcs.go +++ b/float.go @@ -1,7 +1,22 @@ -package softfloat +package randomx import "math" +const ( + mantbits64 uint = 52 + expbits64 uint = 11 +) + +const mantissaMask = (uint64(1) << mantbits64) - 1 +const exponentMask = (uint64(1) << expbits64) - 1 +const exponentBias = 1023 +const dynamicExponentBits = 4 +const staticExponentBits = 4 +const constExponentBits uint64 = 0x300 +const dynamicMantissaMask = (uint64(1) << (mantbits64 + dynamicExponentBits)) - 1 + +const mask22bit = (uint64(1) << 22) - 1 + func MaskRegisterExponentMantissa(f float64, mode uint64) float64 { return math.Float64frombits((math.Float64bits(f) & dynamicMantissaMask) | mode) } diff --git a/go.mod b/go.mod index c4435a4..2899163 100644 --- a/go.mod +++ b/go.mod @@ -5,3 +5,5 @@ go 1.21 require golang.org/x/crypto v0.22.0 require golang.org/x/sys v0.19.0 + +require git.gammaspectra.live/P2Pool/softfloat64 v1.0.0 diff --git a/go.sum b/go.sum index f3d6e98..1e56a51 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +git.gammaspectra.live/P2Pool/softfloat64 v1.0.0 h1:XqxDpowntpV8gvBzG9bMC8VVzxZJT/YEk7BfwmaCamU= +git.gammaspectra.live/P2Pool/softfloat64 v1.0.0/go.mod h1:ZhnGqXOS6F6aJpiiT38Cvk5eHoBNqjkKfp3w3AcnomA= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= diff --git a/register.go b/register.go index fe9f85b..7555ea3 100644 --- a/register.go +++ b/register.go @@ -1,10 +1,5 @@ package randomx -import ( - "git.gammaspectra.live/P2Pool/go-randomx/v2/asm" - "git.gammaspectra.live/P2Pool/go-randomx/v2/softfloat" -) - const RegistersCount = 8 const RegistersCountFloat = 4 @@ -19,15 +14,7 @@ type RegisterFile struct { E [RegistersCountFloat][2]float64 A [RegistersCountFloat][2]float64 - FPRC softfloat.RoundingMode -} - -func (f *RegisterFile) SetRoundingMode(mode softfloat.RoundingMode) { - if f.FPRC == mode { - return - } - f.FPRC = mode - asm.SetRoundingMode(mode) + FPRC uint8 } type MemoryRegisters struct { diff --git a/softfloat/const.go b/softfloat/const.go deleted file mode 100644 index fe15bbf..0000000 --- a/softfloat/const.go +++ /dev/null @@ -1,37 +0,0 @@ -package softfloat - -const ( - mantbits64 uint = 52 - expbits64 uint = 11 - bias64 = -1<<(expbits64-1) + 1 - - nan64 uint64 = (1<