// x87 control-word forcing + timeline sampling (lane F: the precision-sensitivity experiment). // // The question this exists to answer: does any value the turn pipeline produces actually // *depend* on x87 intermediate precision? Every save on the lab host was made with the game's // own control word (0x127f = 53-bit significand, round-to-nearest). A future x64/SSE port has // no 80-bit intermediates at all, so "bit-exact" is only a real constraint if changing the // precision-control field changes the resulting state. // // Method: force the control word once, at the entry to the turn gate, then let the whole // pipeline run under it and checksum the autosave. Forcing is deliberately a *single* write at // the top of the turn -- re-forcing at every hook would guarantee the value is present without // proving it ever held, which is exactly the false-negative this experiment must avoid. // // Verification is separate from forcing: // * every force/sample site logs observed-before, requested, and read-back-after; // * the sampler on DemoApp::OnTick logs the control word on every *change*, per thread, so // shim.log carries a complete timeline of the value for the session rather than a claim; // * the existing hooks (research, colony turn, fleet movement, compute budget) already emit // `fpu_cw` per call, giving independent samples from inside phases 4, 6 and 8 of the turn. // // shim.cfg keys owned here: // fpu.force = 0x027f | 0x127f | 0x137f | control word to force at the turn gate // (absent or 0 = force nothing, sample only) // fpu.sample_ticks = on | off per-tick change sampler (default on) #pragma once #include #include namespace shim::fpu { // Handles the `fpu.*` shim.cfg keys. Returns true when `key` belongs to this module; sets // *err (and leaves the setting unchanged) when the key is ours but the value is unusable. bool apply_config(const char* key, const char* value, std::string* err); // Read the x87 control word of the calling thread. std::uint16_t read_cw(); // One line for shim.log at shutdown: how many times the word was forced, whether any read-back // disagreed, and whether the per-tick sampler ever saw it move away again. std::string summary(); // Installs the force/sample hooks. `log` receives one preformatted line at a time. // Safe to call with no `fpu.force` configured: the sampler still runs, which is what makes a // stock 0x127f run comparable to a forced one. void install(std::uintptr_t exeBase, void (*log)(const char*)); } // namespace shim::fpu