mirror of https://github.com/bsnes-emu/bsnes.git
97 lines
2.2 KiB
C++
97 lines
2.2 KiB
C++
#pragma once
|
|
|
|
namespace Emulator {
|
|
|
|
struct Random {
|
|
enum class Entropy : uint { None, Low, High };
|
|
|
|
auto operator()() -> uint64 {
|
|
return random();
|
|
}
|
|
|
|
auto entropy(Entropy entropy) -> void {
|
|
_entropy = entropy;
|
|
seed();
|
|
}
|
|
|
|
auto seed(maybe<uint32> seed = nothing, maybe<uint32> sequence = nothing) -> void {
|
|
if(!seed) seed = (uint32)clock();
|
|
if(!sequence) sequence = 0;
|
|
|
|
_state = 0;
|
|
_increment = sequence() << 1 | 1;
|
|
step();
|
|
_state += seed();
|
|
step();
|
|
}
|
|
|
|
auto random() -> uint64 {
|
|
if(_entropy == Entropy::None) return 0;
|
|
return (uint64)step() << 32 | (uint64)step() << 0;
|
|
}
|
|
|
|
auto bias(uint64 bias) -> uint64 {
|
|
if(_entropy == Entropy::None) return bias;
|
|
return random();
|
|
}
|
|
|
|
auto bound(uint64 bound) -> uint64 {
|
|
uint64 threshold = -bound % bound;
|
|
while(true) {
|
|
uint64 result = random();
|
|
if(result >= threshold) return result % bound;
|
|
}
|
|
}
|
|
|
|
auto array(uint8* data, uint32 size) -> void {
|
|
if(_entropy == Entropy::None) {
|
|
memory::fill(data, size);
|
|
return;
|
|
}
|
|
|
|
if(_entropy == Entropy::High) {
|
|
for(uint32 address : range(size)) {
|
|
data[address] = random();
|
|
}
|
|
return;
|
|
}
|
|
|
|
//Entropy::Low
|
|
uint lobit = random() & 3;
|
|
uint hibit = (lobit + 8 + (random() & 3)) & 15;
|
|
uint lovalue = random() & 255;
|
|
uint hivalue = random() & 255;
|
|
if((random() & 3) == 0) lovalue = 0;
|
|
if((random() & 1) == 0) hivalue = ~lovalue;
|
|
|
|
for(uint32 address : range(size)) {
|
|
uint8 value = address.bit(lobit) ? lovalue : hivalue;
|
|
if(address.bit(hibit)) value = ~value;
|
|
if((random() & 511) == 0) value.bit(random() & 7) ^= 1;
|
|
if((random() & 2047) == 0) value.bit(random() & 7) ^= 1;
|
|
data[address] = value;
|
|
}
|
|
}
|
|
|
|
auto serialize(serializer& s) -> void {
|
|
s.integer((uint&)_entropy);
|
|
s.integer(_state);
|
|
s.integer(_increment);
|
|
}
|
|
|
|
private:
|
|
auto step() -> uint32 {
|
|
uint64 state = _state;
|
|
_state = state * 6364136223846793005ull + _increment;
|
|
uint32 xorshift = (state >> 18 ^ state) >> 27;
|
|
uint32 rotate = state >> 59;
|
|
return xorshift >> rotate | xorshift << (-rotate & 31);
|
|
}
|
|
|
|
Entropy _entropy = Entropy::High;
|
|
uint64 _state;
|
|
uint64 _increment;
|
|
};
|
|
|
|
}
|