diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 49cd0be7..08df3032 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "104.03"; + static const string Version = "104.04"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/emulator/random.hpp b/higan/emulator/random.hpp new file mode 100644 index 00000000..ff02c08a --- /dev/null +++ b/higan/emulator/random.hpp @@ -0,0 +1,114 @@ +#pragma once + +namespace Emulator { + +struct Random { + enum class Entropy : uint { None, Low, High }; + + auto entropy(Entropy entropy) -> void { + settings.entropy = entropy; + seed(); + } + + auto seed(maybe seed = nothing, maybe sequence = nothing) -> void { + if(!seed) seed = (uint32)clock(); + if(!sequence) sequence = 0; + seed32(seed(), sequence()); + } + + auto operator()() -> uint64 { + return iterate64(); + } + + auto bias(uint64 bias) -> uint64 { + if(settings.entropy == Entropy::None) return bias; + return operator()(); + } + + auto bound(uint64 bound) -> uint64 { + uint64 threshold = -bound % bound; + while(true) { + uint64 result = iterate64(); + if(result >= threshold) return result % bound; + } + } + + auto serialize(serializer& s) -> void { + s.integer((uint&)settings.entropy); + s.integer(ram.state); + s.integer(ram.increment); + s.integer(pcg.state); + s.integer(pcg.increment); + } + +private: + auto seed32(uint32 seed, uint32 sequence) -> void { + switch(settings.entropy) { + + case Entropy::None: { + break; + } + + case Entropy::Low: { + ram.state = seed; + ram.increment = 0; + break; + } + + case Entropy::High: { + pcg.state = 0; + pcg.increment = sequence << 1 | 1; + iterate32(); + pcg.state += seed; + iterate32(); + break; + } + + } + } + + auto iterate32() -> uint32 { + switch(settings.entropy) { + + case Entropy::None: { + return 0; + } + + case Entropy::Low: { + uint64 result = 0; + if(ram.increment.bit(4 + ram.state.bits(0,1))) result = ~0; + ram.increment++; + return result; + } + + case Entropy::High: { + uint64 state = pcg.state; + pcg.state = state * 6364136223846793005ull + pcg.increment; + uint32 xorshift = (state >> 18 ^ state) >> 27; + uint32 rotate = state >> 59; + return xorshift >> rotate | xorshift << (-rotate & 31); + } + + } + } + + auto iterate64() -> uint64 { + return (uint64)iterate32() << 32 | (uint64)iterate32() << 0; + } + + struct Settings { + Entropy entropy = Entropy::High; + } settings; + + struct RAM { //Entropy::Low + uint64 state; + uint64 increment; + } ram; + + struct PCG { //Entropy::High + uint64 state; + uint64 increment; + } pcg; +}; + +} diff --git a/higan/md/vdp/io.cpp b/higan/md/vdp/io.cpp index 40016d0e..d9e3fa6b 100644 --- a/higan/md/vdp/io.cpp +++ b/higan/md/vdp/io.cpp @@ -14,8 +14,8 @@ auto VDP::read(uint24 addr) -> uint16 { //counter case 0xc00008: case 0xc0000a: case 0xc0000c: case 0xc0000e: { auto vcounter = state.vcounter; - if(io.interlaceMode == 3) { - vcounter = vcounter << 1 | state.field; //todo: unverified + if(io.interlaceMode.bit(0)) { + if(io.interlaceMode.bit(1)) vcounter <<= 1; vcounter.bit(0) = vcounter.bit(8); } return vcounter << 8 | (state.hdot >> 1) << 0; diff --git a/higan/sfc/coprocessor/armdsp/armdsp.cpp b/higan/sfc/coprocessor/armdsp/armdsp.cpp index ff63a90d..9c4c396f 100644 --- a/higan/sfc/coprocessor/armdsp/armdsp.cpp +++ b/higan/sfc/coprocessor/armdsp/armdsp.cpp @@ -103,7 +103,8 @@ auto ArmDSP::unload() -> void { } auto ArmDSP::power() -> void { - for(auto n : range(16 * 1024)) programRAM[n] = random(0x00); + random.seed(); + for(auto n : range(16 * 1024)) programRAM[n] = random(); bridge.reset = false; reset(); } diff --git a/higan/sfc/cpu/cpu.cpp b/higan/sfc/cpu/cpu.cpp index ee43f054..00a0ed63 100644 --- a/higan/sfc/cpu/cpu.cpp +++ b/higan/sfc/cpu/cpu.cpp @@ -86,7 +86,8 @@ auto CPU::power() -> void { bus.map(reader, writer, "00-3f,80-bf:0000-1fff", 0x2000); bus.map(reader, writer, "7e-7f:0000-ffff", 0x20000); - for(auto& byte : wram) byte = random(0x55); + random.seed(); + for(auto& byte : wram) byte = random.bias(0x55); //DMA for(auto& channel : this->channel) { diff --git a/higan/sfc/dsp/dsp.cpp b/higan/sfc/dsp/dsp.cpp index b92d65e2..44167c73 100644 --- a/higan/sfc/dsp/dsp.cpp +++ b/higan/sfc/dsp/dsp.cpp @@ -232,7 +232,8 @@ auto DSP::power() -> void { create(Enter, system.apuFrequency()); stream = Emulator::audio.createStream(2, frequency() / 768.0); - for(auto& byte : apuram) byte = random(0x00); + random.seed(); + for(auto& byte : apuram) byte = random(); memory::fill(&state, sizeof(State)); state.noise = 0x4000; diff --git a/higan/sfc/ppu/background/background.cpp b/higan/sfc/ppu/background/background.cpp index be155942..e234c8ab 100644 --- a/higan/sfc/ppu/background/background.cpp +++ b/higan/sfc/ppu/background/background.cpp @@ -207,17 +207,17 @@ auto PPU::Background::getTileColor() -> uint { } auto PPU::Background::power() -> void { - io.tiledataAddress = (random(0x0000) & 0x0f) << 12; - io.screenAddress = (random(0x0000) & 0xfc) << 8; - io.screenSize = random(0); - io.mosaic = random(0); - io.tileSize = random(0); + io.tiledataAddress = (random() & 0x0f) << 12; + io.screenAddress = (random() & 0xfc) << 8; + io.screenSize = random(); + io.mosaic = random(); + io.tileSize = random(); io.mode = 0; for(auto& p : io.priority) p = 0; - io.aboveEnable = random(0); - io.belowEnable = random(0); - io.hoffset = random(0x0000); - io.voffset = random(0x0000); + io.aboveEnable = random(); + io.belowEnable = random(); + io.hoffset = random(); + io.voffset = random(); latch.hoffset = 0; latch.voffset = 0; diff --git a/higan/sfc/ppu/object/object.cpp b/higan/sfc/ppu/object/object.cpp index 9777bd17..c63a6864 100644 --- a/higan/sfc/ppu/object/object.cpp +++ b/higan/sfc/ppu/object/object.cpp @@ -189,13 +189,13 @@ auto PPU::Object::power() -> void { } } - io.aboveEnable = random(false); - io.belowEnable = random(false); - io.interlace = random(false); + io.aboveEnable = random(); + io.belowEnable = random(); + io.interlace = random(); - io.baseSize = random(0); - io.nameselect = random(0); - io.tiledataAddress = (random(0x0000) & 7) << 13; + io.baseSize = random(); + io.nameselect = random(); + io.tiledataAddress = (random() & 7) << 13; io.firstSprite = 0; for(auto& p : io.priority) p = 0; diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp index fefde62c..d4bed152 100644 --- a/higan/sfc/ppu/ppu.cpp +++ b/higan/sfc/ppu/ppu.cpp @@ -95,17 +95,18 @@ auto PPU::power() -> void { function void> writer{&PPU::writeIO, this}; bus.map(reader, writer, "00-3f,80-bf:2100-213f"); - for(auto& n : vram.data) n = random(0x0000); + random.seed(); + for(auto& n : vram.data) n = random(); - ppu1.mdr = random(0xff); - ppu2.mdr = random(0xff); + ppu1.mdr = random.bias(0xff); + ppu2.mdr = random.bias(0xff); - latch.vram = random(0x0000); - latch.oam = random(0x00); - latch.cgram = random(0x00); - latch.bgofsPPU1 = random(0x00); - latch.bgofsPPU2 = random(0x00); - latch.mode7 = random(0x00); + latch.vram = random(); + latch.oam = random(); + latch.cgram = random(); + latch.bgofsPPU1 = random(); + latch.bgofsPPU2 = random(); + latch.mode7 = random(); latch.counters = false; latch.hcounter = 0; latch.vcounter = 0; @@ -119,59 +120,59 @@ auto PPU::power() -> void { //$2102 OAMADDL //$2103 OAMADDH - io.oamBaseAddress = random(0x0000); - io.oamAddress = random(0x0000); - io.oamPriority = random(false); + io.oamBaseAddress = random(); + io.oamAddress = random(); + io.oamPriority = random(); //$2105 BGMODE io.bgPriority = false; io.bgMode = 0; //$210d BG1HOFS - io.hoffsetMode7 = random(0x0000); + io.hoffsetMode7 = random(); //$210e BG1VOFS - io.voffsetMode7 = random(0x0000); + io.voffsetMode7 = random(); //$2115 VMAIN - io.vramIncrementMode = random(1); - io.vramMapping = random(0); + io.vramIncrementMode = random.bias(1); + io.vramMapping = random(); io.vramIncrementSize = 1; //$2116 VMADDL //$2117 VMADDH - io.vramAddress = random(0x0000); + io.vramAddress = random(); //$211a M7SEL - io.repeatMode7 = random(0); - io.vflipMode7 = random(false); - io.hflipMode7 = random(false); + io.repeatMode7 = random(); + io.vflipMode7 = random(); + io.hflipMode7 = random(); //$211b M7A - io.m7a = random(0x0000); + io.m7a = random(); //$211c M7B - io.m7b = random(0x0000); + io.m7b = random(); //$211d M7C - io.m7c = random(0x0000); + io.m7c = random(); //$211e M7D - io.m7d = random(0x0000); + io.m7d = random(); //$211f M7X - io.m7x = random(0x0000); + io.m7x = random(); //$2120 M7Y - io.m7y = random(0x0000); + io.m7y = random(); //$2121 CGADD - io.cgramAddress = random(0x00); - io.cgramAddressLatch = random(0); + io.cgramAddress = random(); + io.cgramAddressLatch = random(); //$2133 SETINI - io.extbg = random(false); - io.pseudoHires = random(false); + io.extbg = random(); + io.pseudoHires = random(); io.overscan = false; io.interlace = false; diff --git a/higan/sfc/ppu/screen/screen.cpp b/higan/sfc/ppu/screen/screen.cpp index bc2cac01..769dba2f 100644 --- a/higan/sfc/ppu/screen/screen.cpp +++ b/higan/sfc/ppu/screen/screen.cpp @@ -161,19 +161,20 @@ auto PPU::Screen::fixedColor() const -> uint15 { } auto PPU::Screen::power() -> void { - for(auto& n : cgram) n = random(0x0000); + random.seed(); + for(auto& n : cgram) n = random(); - io.blendMode = random(false); - io.directColor = random(false); - io.colorMode = random(false); - io.colorHalve = random(false); - io.bg1.colorEnable = random(false); - io.bg2.colorEnable = random(false); - io.bg3.colorEnable = random(false); - io.bg4.colorEnable = random(false); - io.obj.colorEnable = random(false); - io.back.colorEnable = random(false); - io.colorBlue = random(0); - io.colorGreen = random(0); - io.colorRed = random(0); + io.blendMode = random(); + io.directColor = random(); + io.colorMode = random(); + io.colorHalve = random(); + io.bg1.colorEnable = random(); + io.bg2.colorEnable = random(); + io.bg3.colorEnable = random(); + io.bg4.colorEnable = random(); + io.obj.colorEnable = random(); + io.back.colorEnable = random(); + io.colorBlue = random(); + io.colorGreen = random(); + io.colorRed = random(); } diff --git a/higan/sfc/ppu/window/window.cpp b/higan/sfc/ppu/window/window.cpp index 8fd2e442..96d83d51 100644 --- a/higan/sfc/ppu/window/window.cpp +++ b/higan/sfc/ppu/window/window.cpp @@ -47,58 +47,58 @@ auto PPU::Window::test(bool oneEnable, bool one, bool twoEnable, bool two, uint } auto PPU::Window::power() -> void { - io.bg1.oneEnable = random(false); - io.bg1.oneInvert = random(false); - io.bg1.twoEnable = random(false); - io.bg1.twoInvert = random(false); - io.bg1.mask = random(0); - io.bg1.aboveEnable = random(false); - io.bg1.belowEnable = random(false); + io.bg1.oneEnable = random(); + io.bg1.oneInvert = random(); + io.bg1.twoEnable = random(); + io.bg1.twoInvert = random(); + io.bg1.mask = random(); + io.bg1.aboveEnable = random(); + io.bg1.belowEnable = random(); - io.bg2.oneEnable = random(false); - io.bg2.oneInvert = random(false); - io.bg2.twoEnable = random(false); - io.bg2.twoInvert = random(false); - io.bg2.mask = random(0); - io.bg2.aboveEnable = random(false); - io.bg2.belowEnable = random(false); + io.bg2.oneEnable = random(); + io.bg2.oneInvert = random(); + io.bg2.twoEnable = random(); + io.bg2.twoInvert = random(); + io.bg2.mask = random(); + io.bg2.aboveEnable = random(); + io.bg2.belowEnable = random(); - io.bg3.oneEnable = random(false); - io.bg3.oneInvert = random(false); - io.bg3.twoEnable = random(false); - io.bg3.twoInvert = random(false); - io.bg3.mask = random(0); - io.bg3.aboveEnable = random(false); - io.bg3.belowEnable = random(false); + io.bg3.oneEnable = random(); + io.bg3.oneInvert = random(); + io.bg3.twoEnable = random(); + io.bg3.twoInvert = random(); + io.bg3.mask = random(); + io.bg3.aboveEnable = random(); + io.bg3.belowEnable = random(); - io.bg4.oneEnable = random(false); - io.bg4.oneInvert = random(false); - io.bg4.twoEnable = random(false); - io.bg4.twoInvert = random(false); - io.bg4.mask = random(0); - io.bg4.aboveEnable = random(false); - io.bg4.belowEnable = random(false); + io.bg4.oneEnable = random(); + io.bg4.oneInvert = random(); + io.bg4.twoEnable = random(); + io.bg4.twoInvert = random(); + io.bg4.mask = random(); + io.bg4.aboveEnable = random(); + io.bg4.belowEnable = random(); - io.obj.oneEnable = random(false); - io.obj.oneInvert = random(false); - io.obj.twoEnable = random(false); - io.obj.twoInvert = random(false); - io.obj.mask = random(0); - io.obj.aboveEnable = random(false); - io.obj.belowEnable = random(false); + io.obj.oneEnable = random(); + io.obj.oneInvert = random(); + io.obj.twoEnable = random(); + io.obj.twoInvert = random(); + io.obj.mask = random(); + io.obj.aboveEnable = random(); + io.obj.belowEnable = random(); - io.col.oneEnable = random(false); - io.col.oneInvert = random(false); - io.col.twoEnable = random(false); - io.col.twoInvert = random(false); - io.col.mask = random(0); - io.col.aboveMask = random(0); - io.col.belowMask = random(0); + io.col.oneEnable = random(); + io.col.oneInvert = random(); + io.col.twoEnable = random(); + io.col.twoInvert = random(); + io.col.mask = random(); + io.col.aboveMask = random(); + io.col.belowMask = random(); - io.oneLeft = random(0x00); - io.oneRight = random(0x00); - io.twoLeft = random(0x00); - io.twoRight = random(0x00); + io.oneLeft = random(); + io.oneRight = random(); + io.twoLeft = random(); + io.twoRight = random(); output.above.colorEnable = 0; output.below.colorEnable = 0; diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp index 176f5dca..77b3378c 100644 --- a/higan/sfc/sfc.hpp +++ b/higan/sfc/sfc.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -23,8 +24,10 @@ namespace SuperFamicom { #define platform Emulator::platform namespace File = Emulator::File; using Scheduler = Emulator::Scheduler; + using Random = Emulator::Random; using Cheat = Emulator::Cheat; extern Scheduler scheduler; + extern Random random; extern Cheat cheat; struct Thread : Emulator::Thread { diff --git a/higan/sfc/system/random.cpp b/higan/sfc/system/random.cpp deleted file mode 100644 index 5e68546c..00000000 --- a/higan/sfc/system/random.cpp +++ /dev/null @@ -1,14 +0,0 @@ -Random random; - -auto Random::seed(uint seed) -> void { - iter = seed; -} - -auto Random::operator()(uint result) -> uint { - if(!settings.random) return result; - return iter = (iter >> 1) ^ (((iter & 1) - 1) & 0xedb88320); -} - -auto Random::serialize(serializer& s) -> void { - s.integer(iter); -} diff --git a/higan/sfc/system/serialization.cpp b/higan/sfc/system/serialization.cpp index 6f0f5463..b3e6cf3f 100644 --- a/higan/sfc/system/serialization.cpp +++ b/higan/sfc/system/serialization.cpp @@ -42,9 +42,9 @@ auto System::serialize(serializer& s) -> void { } auto System::serializeAll(serializer& s) -> void { + random.serialize(s); cartridge.serialize(s); system.serialize(s); - random.serialize(s); cpu.serialize(s); smp.serialize(s); ppu.serialize(s); diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index a1d13ee4..62c8c3e6 100644 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -4,9 +4,9 @@ namespace SuperFamicom { System system; Scheduler scheduler; +Random random; Cheat cheat; #include "video.cpp" -#include "random.cpp" #include "serialization.cpp" auto System::run() -> void { @@ -141,7 +141,7 @@ auto System::power() -> void { Emulator::audio.reset(); Emulator::audio.setInterface(interface); - random.seed((uint)time(0)); + random.entropy(Random::Entropy::High); scheduler.reset(); cpu.power(); diff --git a/higan/sfc/system/system.hpp b/higan/sfc/system/system.hpp index b5e5f5e9..e54d592e 100644 --- a/higan/sfc/system/system.hpp +++ b/higan/sfc/system/system.hpp @@ -44,17 +44,7 @@ private: friend class Cartridge; }; -struct Random { - auto seed(uint seed) -> void; - auto operator()(uint result) -> uint; - auto serialize(serializer& s) -> void; - -private: - uint iter = 0; -}; - extern System system; -extern Random random; auto Region::NTSC() -> bool { return system.region() == System::Region::NTSC; } auto Region::PAL() -> bool { return system.region() == System::Region::PAL; }