| 6 | |
| 7 | namespace mkpivm { |
| 8 | VMConfig::VMConfig(Arch arch, SeedRng& rng) : arch_{arch}, master_seed_{rng.next()} { |
| 9 | // register file shape |
| 10 | // need 16 arch gprs + 4 tmps + at least 4 scratch = 24 minimum |
| 11 | reg_count_ = static_cast<std::uint8_t>(rng.uniform(24, 32)); |
| 12 | |
| 13 | // XReg to slot mapping. random permutation over 0..reg_count_-1 with |
| 14 | // the first 16 reserved for x86 gprs |
| 15 | std::vector<std::uint8_t> perm(reg_count_); |
| 16 | for (std::uint8_t i = 0; i < reg_count_; ++i) perm[i] = i; |
| 17 | shuffle_in_place(perm, rng); |
| 18 | |
| 19 | const std::uint8_t gpr_count = arch_native_gpr_count(arch); |
| 20 | xreg_to_slot_.fill(0xFF); |
| 21 | for (std::uint8_t i = 0; i < gpr_count; ++i) { |
| 22 | xreg_to_slot_[i] = perm[i]; |
| 23 | } |
| 24 | |
| 25 | // four slots for Tmp0..Tmp3. these sit past the arch gprs |
| 26 | const std::uint8_t tmp_count = 4; |
| 27 | for (std::uint8_t i = 0; i < tmp_count; ++i) { |
| 28 | xreg_to_slot_[16 + i] = perm[gpr_count + i]; |
| 29 | } |
| 30 | scratch_slots_.assign(perm.begin() + gpr_count + tmp_count, perm.begin() + reg_count_); |
| 31 | |
| 32 | // VMState layout. fields go in random order |
| 33 | auto pad = [&](std::uint16_t cur, std::uint16_t align) { |
| 34 | const std::uint16_t over = cur % align; |
| 35 | return over ? static_cast<std::uint16_t>(cur + (align - over)) : cur; |
| 36 | }; |
| 37 | |
| 38 | auto sprinkle_gap = [&](std::uint16_t cur)->std::uint16_t { |
| 39 | return cur + static_cast<std::uint16_t>(rng.uniform(0, 7)); |
| 40 | }; |
| 41 | |
| 42 | std::uint16_t cur = static_cast<std::uint16_t>(rng.uniform(0, 31)); // random initial offset |
| 43 | cur = pad(cur, 8); |
| 44 | |
| 45 | // reg-slot array. |
| 46 | state_.regs_base = cur; |
| 47 | state_.regs_total_bytes = static_cast<std::uint16_t>(reg_count_ * 8); |
| 48 | cur = static_cast<std::uint16_t>(cur + state_.regs_total_bytes); |
| 49 | |
| 50 | // scalar fields, placed in random order. |
| 51 | enum Field { F_OP, F_A, F_B, F_RES, F_W, F_DF, F_CSP, F_RSP, F_BCB, F_DIB, F_BTB, F_BTC, F_TRB, F_EXT, F_CSB, F_END }; |
| 52 | std::array<std::uint8_t, F_END> order{}; |
| 53 | for (std::uint8_t i = 0; i < F_END; ++i) order[i] = i; |
| 54 | shuffle_in_place(order, rng); |
| 55 | |
| 56 | for (auto f : order) { |
| 57 | cur = sprinkle_gap(cur); |
| 58 | cur = pad(cur, 8); |
| 59 | switch (f) { |
| 60 | case F_OP: state_.flags_op = cur; cur += 8; break; |
| 61 | case F_A: state_.flags_a = cur; cur += 8; break; |
| 62 | case F_B: state_.flags_b = cur; cur += 8; break; |
| 63 | case F_RES: state_.flags_result = cur; cur += 8; break; |
| 64 | case F_W: state_.flags_width = cur; cur += 8; break; |
| 65 | case F_DF: state_.df = cur; cur += 8; break; |
nothing calls this directly
no test coverage detected