Skip to main content

rustdom_x/
vm.rs

1extern crate blake2b_simd;
2
3use self::blake2b_simd::{Hash, Params, blake2b};
4use super::common::{mulh, randomx_reciprocal, smulh, u64_from_i32_imm};
5use super::hash::{fill_aes_1rx4_u64, gen_program_aes_4rx4, hash_aes_1rx4};
6use super::m128::{m128d, m128i};
7use super::memory::{CACHE_LINE_SIZE, VmMemory};
8use super::program::{Instr, MAX_FLOAT_REG, MAX_REG, Mode, Program, Store};
9use std::convert::TryInto;
10use std::sync::Arc;
11
12fn set_rounding_mode_env(mode: u32) {
13    #[cfg(target_arch = "x86_64")]
14    unsafe {
15        let fe_mode: u32 = match mode {
16            1 => 0x400,
17            2 => 0x800,
18            3 => 0xC00,
19            _ => 0,
20        };
21        let mut mxcsr: u32 = 0;
22        std::arch::asm!("stmxcsr [{0}]", in(reg) &mut mxcsr as *mut u32, options(nostack));
23        mxcsr = (mxcsr & !0x6000) | (fe_mode & 0x6000);
24        std::arch::asm!("ldmxcsr [{0}]", in(reg) &mxcsr as *const u32, options(nostack));
25    }
26
27    #[cfg(target_arch = "aarch64")]
28    unsafe {
29        let arm_mode: u64 = match mode {
30            1 => 0b10, // RM - toward minus inf
31            2 => 0b01, // RP - toward plus inf
32            3 => 0b11, // RZ - toward zero
33            _ => 0b00, // RN - nearest
34        };
35        let mut fpcr: u64;
36        std::arch::asm!("mrs {}, fpcr", out(reg) fpcr);
37        fpcr = (fpcr & !(0b11 << 22)) | (arm_mode << 22);
38        std::arch::asm!("msr fpcr, {}", in(reg) fpcr);
39    }
40}
41
42pub const SCRATCHPAD_L1_MASK: u64 = 0x3ff8;
43pub const SCRATCHPAD_L2_MASK: u64 = 0x3fff8;
44pub const SCRATCHPAD_L3_MASK: u64 = 0x1ffff8;
45const SCRATCHPAD_L3_MASK_U32: u32 = 0x1fffc0;
46
47const SCRATCHPAD_SIZE: usize = 262144;
48const MXCSR_DEFAULT: u32 = 0x9FC0;
49const CONDITION_OFFSET: u64 = 8;
50const CONDITION_MASK: u64 = (1 << CONDITION_OFFSET) - 1;
51
52const RANDOMX_PROGRAM_COUNT: usize = 8;
53const RANDOMX_PROGRAM_SIZE: i32 = 256;
54const RANDOMX_PROGRAM_ITERATIONS: usize = 2048;
55const RANDOMX_DATASET_BASE_SIZE: usize = 2147483648;
56const RANDOMX_DATASET_ITEM_SIZE: usize = 64;
57const RANDOMX_DATASET_EXTRA_SIZE: usize = 33554368;
58const RANDOMX_HASH_SIZE: usize = 32;
59
60const DATASET_EXTRA_ITEMS: usize = RANDOMX_DATASET_EXTRA_SIZE / RANDOMX_DATASET_ITEM_SIZE;
61
62const MANTISSA_SIZE: u64 = 52;
63const MANTISSA_MASK: u64 = (1 << MANTISSA_SIZE) - 1;
64const EXPONENT_SIZE: u64 = 11;
65const EXPONENT_BIAS: u64 = 1023;
66const EXPONENT_MASK: u64 = (1 << EXPONENT_SIZE) - 1;
67const EXPONENT_BITS: u64 = 0x300;
68const DYNAMIC_EXPONENT_BITS: u64 = 4;
69const STATIC_EXPONENT_BITS: u64 = 4;
70const DYNAMIC_MANTISSA_MASK: u64 = (1 << (MANTISSA_SIZE + DYNAMIC_EXPONENT_BITS)) - 1;
71
72const CACHE_LINE_ALIGN_MASK: u64 =
73    ((RANDOMX_DATASET_BASE_SIZE - 1) & !(RANDOMX_DATASET_ITEM_SIZE - 1)) as u64;
74
75pub struct MemoryRegister {
76    pub mx: usize,
77    pub ma: usize,
78}
79
80pub struct Register {
81    pub r: [u64; MAX_REG as usize],
82    pub f: [m128d; MAX_FLOAT_REG as usize],
83    pub e: [m128d; MAX_FLOAT_REG as usize],
84    pub a: [m128d; MAX_FLOAT_REG as usize],
85}
86
87pub fn new_register() -> Register {
88    Register {
89        r: [0; MAX_REG as usize],
90        f: [m128d::zero(); MAX_FLOAT_REG as usize],
91        e: [m128d::zero(); MAX_FLOAT_REG as usize],
92        a: [m128d::zero(); MAX_FLOAT_REG as usize],
93    }
94}
95
96impl Register {
97    pub fn to_bytes(&self) -> [u8; 256] {
98        let mut bytes = [0; 256];
99        let mut offset = 0;
100        for i in 0..MAX_REG {
101            Register::copy_into_le(&mut bytes, offset, self.r[i]);
102            offset += 1;
103        }
104
105        for i in 0..MAX_FLOAT_REG {
106            let (h, l) = self.f[i].as_u64();
107            Register::copy_into_le(&mut bytes, offset, l);
108            offset += 1;
109            Register::copy_into_le(&mut bytes, offset, h);
110            offset += 1;
111        }
112
113        for i in 0..MAX_FLOAT_REG {
114            let (h, l) = self.e[i].as_u64();
115            Register::copy_into_le(&mut bytes, offset, l);
116            offset += 1;
117            Register::copy_into_le(&mut bytes, offset, h);
118            offset += 1;
119        }
120
121        for i in 0..MAX_FLOAT_REG {
122            let (h, l) = self.a[i].as_u64();
123            Register::copy_into_le(&mut bytes, offset, l);
124            offset += 1;
125            Register::copy_into_le(&mut bytes, offset, h);
126            offset += 1;
127        }
128
129        bytes
130    }
131
132    fn copy_into_le(bytes: &mut [u8; 256], offset: usize, u: u64) {
133        let reg_bytes = u.to_le_bytes();
134        for k in 0..8 {
135            bytes[offset * 8 + k] = reg_bytes[k];
136        }
137    }
138}
139
140pub struct VmConfig {
141    pub e_mask: [u64; 2],
142    pub read_reg: [usize; 4],
143}
144
145pub struct Vm {
146    pub mem_reg: MemoryRegister,
147    pub reg: Register,
148    pub scratchpad: Vec<u64>,
149    pub pc: i32,
150    pub config: VmConfig,
151    pub mem: Arc<VmMemory>,
152    pub dataset_offset: u64,
153    mxcsr: u32,
154}
155
156impl Vm {
157    pub fn init_vm(&mut self, prog: &Program) {
158        self.reg.a[0] = m128d::from_u64(
159            small_positive_float_bit(prog.entropy[1]),
160            small_positive_float_bit(prog.entropy[0]),
161        );
162        self.reg.a[1] = m128d::from_u64(
163            small_positive_float_bit(prog.entropy[3]),
164            small_positive_float_bit(prog.entropy[2]),
165        );
166        self.reg.a[2] = m128d::from_u64(
167            small_positive_float_bit(prog.entropy[5]),
168            small_positive_float_bit(prog.entropy[4]),
169        );
170        self.reg.a[3] = m128d::from_u64(
171            small_positive_float_bit(prog.entropy[7]),
172            small_positive_float_bit(prog.entropy[6]),
173        );
174
175        self.mem_reg.ma = ((prog.entropy[8] & CACHE_LINE_ALIGN_MASK) as u32) as usize;
176        self.mem_reg.mx = (prog.entropy[10] as u32) as usize;
177
178        let mut address_reg = prog.entropy[12] as usize;
179        self.config.read_reg[0] = address_reg & 1;
180        address_reg >>= 1;
181        self.config.read_reg[1] = 2 + (address_reg & 1);
182        address_reg >>= 1;
183        self.config.read_reg[2] = 4 + (address_reg & 1);
184        address_reg >>= 1;
185        self.config.read_reg[3] = 6 + (address_reg & 1);
186
187        self.dataset_offset =
188            (prog.entropy[13] % (DATASET_EXTRA_ITEMS as u64 + 1)) * CACHE_LINE_SIZE;
189
190        self.config.e_mask[0] = float_mask(prog.entropy[14]);
191        self.config.e_mask[1] = float_mask(prog.entropy[15]);
192
193        for i in 0..MAX_REG {
194            self.reg.r[i] = 0;
195        }
196    }
197
198    pub fn init_scratchpad(&mut self, seed: &[m128i; 4]) -> [m128i; 4] {
199        fill_aes_1rx4_u64(seed, &mut self.scratchpad)
200    }
201
202    pub fn calculate_hash(&mut self, input: &[u8]) -> Hash {
203        let hash = blake2b(input);
204        let seed = hash_to_m128i_array(&hash);
205
206        let mut tmp_hash = self.init_scratchpad(&seed);
207        self.reset_rounding_mode();
208
209        for _ in 0..(RANDOMX_PROGRAM_COUNT - 1) {
210            self.run(&tmp_hash);
211            let blake_result = blake2b(&self.reg.to_bytes());
212            tmp_hash = hash_to_m128i_array(&blake_result);
213        }
214
215        self.run(&tmp_hash);
216        let final_hash = hash_aes_1rx4(&self.scratchpad);
217        self.reg.a[0] = final_hash[0].as_m128d();
218        self.reg.a[1] = final_hash[1].as_m128d();
219        self.reg.a[2] = final_hash[2].as_m128d();
220        self.reg.a[3] = final_hash[3].as_m128d();
221
222        let mut params = Params::new();
223        params.hash_length(RANDOMX_HASH_SIZE);
224        params.hash(&self.reg.to_bytes())
225    }
226
227    /// Runs one round
228    pub fn run(&mut self, seed: &[m128i; 4]) {
229        let prog = Program::from_bytes(gen_program_aes_4rx4(seed, 136));
230
231        self.init_vm(&prog);
232
233        let mut sp_addr_0: u32 = self.mem_reg.mx as u32;
234        let mut sp_addr_1: u32 = self.mem_reg.ma as u32;
235
236        for _ in 0..RANDOMX_PROGRAM_ITERATIONS {
237            let sp_mix = self.reg.r[self.config.read_reg[0]] ^ self.reg.r[self.config.read_reg[1]];
238
239            sp_addr_0 ^= sp_mix as u32;
240            sp_addr_0 &= SCRATCHPAD_L3_MASK_U32;
241            sp_addr_0 /= 8;
242            sp_addr_1 ^= (sp_mix >> 32) as u32;
243            sp_addr_1 &= SCRATCHPAD_L3_MASK_U32;
244            sp_addr_1 /= 8;
245
246            for i in 0..MAX_REG {
247                self.reg.r[i] ^= self.scratchpad[sp_addr_0 as usize + i];
248            }
249            for i in 0..MAX_FLOAT_REG {
250                self.reg.f[i] =
251                    m128i::from_u64(0, self.scratchpad[sp_addr_1 as usize + i]).lower_to_m128d();
252            }
253            for i in 0..MAX_FLOAT_REG {
254                self.reg.e[i] = self.mask_register_exponent_mantissa(
255                    m128i::from_u64(0, self.scratchpad[sp_addr_1 as usize + i + MAX_FLOAT_REG])
256                        .lower_to_m128d(),
257                );
258            }
259
260            self.pc = 0;
261            while self.pc < RANDOMX_PROGRAM_SIZE {
262                let instr = &prog.program[self.pc as usize];
263                instr.execute(self);
264                self.pc += 1;
265            }
266
267            self.mem_reg.mx ^= (self.reg.r[self.config.read_reg[2]]
268                ^ self.reg.r[self.config.read_reg[3]]) as usize;
269            self.mem_reg.mx &= CACHE_LINE_ALIGN_MASK as usize;
270            self.mem.dataset_read(
271                self.dataset_offset + self.mem_reg.ma as u64,
272                &mut self.reg.r,
273            );
274
275            std::mem::swap(&mut self.mem_reg.mx, &mut self.mem_reg.ma);
276
277            for i in 0..MAX_REG {
278                self.scratchpad[sp_addr_1 as usize + i] = self.reg.r[i];
279            }
280            for i in 0..MAX_FLOAT_REG {
281                self.reg.f[i] = self.reg.f[i] ^ self.reg.e[i];
282            }
283
284            for i in 0..MAX_FLOAT_REG {
285                let (u1, u0) = self.reg.f[i].as_u64();
286                let ix = sp_addr_0 as usize + 2 * i;
287                self.scratchpad[ix] = u0;
288                self.scratchpad[ix + 1] = u1;
289            }
290            sp_addr_0 = 0;
291            sp_addr_1 = 0;
292        }
293    }
294
295    pub fn reset_rounding_mode(&mut self) {
296        self.mxcsr = MXCSR_DEFAULT;
297        set_rounding_mode_env(0);
298    }
299
300    pub fn set_rounding_mode(&mut self, mode: u32) {
301        self.mxcsr = MXCSR_DEFAULT | (mode << 13);
302        set_rounding_mode_env(mode);
303    }
304
305    pub fn get_rounding_mode(&self) -> u32 {
306        (self.mxcsr >> 13) & 3
307    }
308
309    //f...
310
311    pub fn exec_fswap_r(&mut self, instr: &Instr) {
312        let v_dst = self.read_float_reg(&instr.dst);
313        self.write_float_reg(&instr.dst, v_dst.shuffle_1(&v_dst));
314    }
315
316    pub fn exec_fadd_r(&mut self, instr: &Instr) {
317        let v_src = self.read_a(&instr.src);
318        let v_dst = self.read_f(&instr.dst);
319        self.write_f(&instr.dst, v_src + v_dst);
320    }
321
322    pub fn exec_fadd_m(&mut self, instr: &Instr) {
323        let v = self.scratchpad[self.scratchpad_src_ix(instr)];
324        let v_src = m128i::from_u64(0, v).lower_to_m128d();
325        let v_dst = self.read_f(&instr.dst);
326        self.write_f(&instr.dst, v_dst + v_src);
327    }
328
329    pub fn exec_fsub_r(&mut self, instr: &Instr) {
330        let v_src = self.read_a(&instr.src);
331        let v_dst = self.read_f(&instr.dst);
332        self.write_f(&instr.dst, v_dst - v_src);
333    }
334
335    pub fn exec_fsub_m(&mut self, instr: &Instr) {
336        let v = self.scratchpad[self.scratchpad_src_ix(instr)];
337        let v_src = m128i::from_u64(0, v).lower_to_m128d();
338        let v_dst = self.read_f(&instr.dst);
339        self.write_f(&instr.dst, v_dst - v_src);
340    }
341
342    pub fn exec_fscal_r(&mut self, instr: &Instr) {
343        let v_dst = self.read_f(&instr.dst);
344        let mask = m128d::from_u64(0x80F0000000000000, 0x80F0000000000000);
345        self.write_f(&instr.dst, v_dst ^ mask);
346    }
347
348    pub fn exec_fmul_r(&mut self, instr: &Instr) {
349        let v_src = self.read_a(&instr.src);
350        let v_dst = self.read_e(&instr.dst);
351        self.write_e(&instr.dst, v_src * v_dst);
352    }
353
354    pub fn exec_fsqrt_r(&mut self, instr: &Instr) {
355        let v_dst = self.read_e(&instr.dst);
356        self.write_e(&instr.dst, v_dst.sqrt());
357    }
358
359    pub fn exec_fdiv_m(&mut self, instr: &Instr) {
360        let v = self.scratchpad[self.scratchpad_src_ix(instr)];
361        let v_src = self.mask_register_exponent_mantissa(m128i::from_u64(0, v).lower_to_m128d());
362        let v_dst = self.read_e(&instr.dst);
363        self.write_e(&instr.dst, v_dst / v_src);
364    }
365
366    //i...
367
368    pub fn exec_iadd_m(&mut self, instr: &Instr) {
369        let ix = self.scratchpad_src_ix(instr);
370        self.write_r(
371            &instr.dst,
372            self.read_r(&instr.dst).wrapping_add(self.scratchpad[ix]),
373        );
374    }
375
376    pub fn exec_isub_m(&mut self, instr: &Instr) {
377        let ix = self.scratchpad_src_ix(instr);
378        self.write_r(
379            &instr.dst,
380            self.read_r(&instr.dst).wrapping_sub(self.scratchpad[ix]),
381        );
382    }
383
384    pub fn exec_imul_m(&mut self, instr: &Instr) {
385        let ix = self.scratchpad_src_ix(instr);
386        self.write_r(
387            &instr.dst,
388            self.read_r(&instr.dst).wrapping_mul(self.scratchpad[ix]),
389        );
390    }
391    pub fn exec_iadd_rs(&mut self, instr: &Instr) {
392        let mut v = self.read_r(&instr.src) << shift_mode(instr);
393        if let Some(imm) = instr.imm {
394            v = v.wrapping_add(u64_from_i32_imm(imm));
395        }
396        self.write_r(&instr.dst, self.read_r(&instr.dst).wrapping_add(v));
397    }
398    pub fn exec_isub_r(&mut self, instr: &Instr) {
399        let v = self.imm_or_r(instr);
400        self.write_r(&instr.dst, self.read_r(&instr.dst).wrapping_sub(v));
401    }
402
403    pub fn exec_imul_r(&mut self, instr: &Instr) {
404        let v = self.imm_or_r(instr);
405        self.write_r(&instr.dst, self.read_r(&instr.dst).wrapping_mul(v));
406    }
407
408    pub fn exec_imul_rcp(&mut self, instr: &Instr) {
409        if !is_zero_or_power_of_2(instr.imm.unwrap() as u64) {
410            let v = randomx_reciprocal((instr.imm.unwrap() as u64) & 0x00000000FFFFFFFF);
411            self.write_r(&instr.dst, self.read_r(&instr.dst).wrapping_mul(v));
412        } //else: nop
413    }
414
415    pub fn exec_imulh_r(&mut self, instr: &Instr) {
416        let v_src = self.read_r(&instr.src);
417        let v_dst = self.read_r(&instr.dst);
418        self.write_r(&instr.dst, mulh(v_src, v_dst));
419    }
420
421    pub fn exec_imulh_m(&mut self, instr: &Instr) {
422        let v_dst = self.read_r(&instr.dst);
423        let v_src = self.scratchpad[self.scratchpad_src_ix(instr)];
424        self.write_r(&instr.dst, mulh(v_src, v_dst));
425    }
426
427    pub fn exec_ismulh_r(&mut self, instr: &Instr) {
428        let v_src = self.read_r(&instr.src);
429        let v_dst = self.read_r(&instr.dst);
430        self.write_r(&instr.dst, smulh(v_src, v_dst));
431    }
432
433    pub fn exec_ismulh_m(&mut self, instr: &Instr) {
434        let v_src = self.scratchpad[self.scratchpad_src_ix(instr)];
435        let v_dst = self.read_r(&instr.dst);
436        self.write_r(&instr.dst, smulh(v_src, v_dst));
437    }
438
439    pub fn exec_ineg_r(&mut self, instr: &Instr) {
440        let v_dst = self.read_r(&instr.dst);
441        self.write_r(&instr.dst, (!v_dst).wrapping_add(1));
442    }
443
444    pub fn exec_ixor_r(&mut self, instr: &Instr) {
445        let v_src = self.imm_or_r(instr);
446        let v_dst = self.read_r(&instr.dst);
447        self.write_r(&instr.dst, v_dst ^ v_src);
448    }
449
450    pub fn exec_ixor_m(&mut self, instr: &Instr) {
451        let v_src = self.scratchpad[self.scratchpad_src_ix(instr)];
452        let v_dst = self.read_r(&instr.dst);
453        self.write_r(&instr.dst, v_dst ^ v_src);
454    }
455
456    pub fn exec_iror_r(&mut self, instr: &Instr) {
457        let v_src = (self.imm_or_r(instr) & 0xFFFFFF) as u32;
458        let v_dst = self.read_r(&instr.dst);
459        self.write_r(&instr.dst, v_dst.rotate_right(v_src));
460    }
461
462    pub fn exec_irol_r(&mut self, instr: &Instr) {
463        let v_src = (self.imm_or_r(instr) & 0xFFFFFF) as u32;
464        let v_dst = self.read_r(&instr.dst);
465        self.write_r(&instr.dst, v_dst.rotate_left(v_src));
466    }
467
468    pub fn exec_iswap_r(&mut self, instr: &Instr) {
469        let v_src = self.read_r(&instr.src);
470        let v_dst = self.read_r(&instr.dst);
471        self.write_r(&instr.dst, v_src);
472        self.write_r(&instr.src, v_dst);
473    }
474
475    pub fn exec_istore(&mut self, instr: &Instr) {
476        let ix = self.scratchpad_dst_ix(instr);
477        self.scratchpad[ix] = self.read_r(&instr.src);
478    }
479
480    //c..
481
482    pub fn exec_cfround(&mut self, instr: &Instr) {
483        let v_src = self.read_r(&instr.src);
484        let mode = (v_src.rotate_right(instr.imm.unwrap() as u32) % 4) as u32;
485        self.set_rounding_mode(mode);
486    }
487
488    pub fn exec_cbranch(&mut self, instr: &Instr) {
489        let shift = cond_mode(instr) as u64 + CONDITION_OFFSET;
490        let mut imm = u64_from_i32_imm(instr.imm.unwrap()) | 1 << shift;
491        if CONDITION_OFFSET > 0 || shift > 0 {
492            imm &= !(1 << (shift - 1));
493        }
494        let v_dst = self.read_r(&instr.dst).wrapping_add(imm);
495        self.write_r(&instr.dst, v_dst);
496        if v_dst & (CONDITION_MASK << shift) == 0 {
497            self.pc = instr.target.unwrap();
498        }
499    }
500
501    //helper
502
503    fn imm_or_r(&self, instr: &Instr) -> u64 {
504        if instr.src == Store::NONE {
505            return instr.imm.unwrap() as u64;
506        }
507        self.read_r(&instr.src)
508    }
509
510    fn read_float_reg(&self, store: &Store) -> m128d {
511        match store {
512            Store::A(i) => self.reg.a[*i],
513            Store::E(i) => self.reg.e[*i],
514            Store::F(i) => self.reg.f[*i],
515            _ => panic!("illegal read from float register"),
516        }
517    }
518
519    fn write_float_reg(&mut self, store: &Store, v: m128d) {
520        match store {
521            Store::A(i) => self.reg.a[*i] = v,
522            Store::E(i) => self.reg.e[*i] = v,
523            Store::F(i) => self.reg.f[*i] = v,
524            _ => panic!("illegal write to float register"),
525        }
526    }
527
528    fn read_r(&self, store: &Store) -> u64 {
529        match store {
530            Store::R(i) => self.reg.r[*i],
531            _ => panic!("illegal read from register r"),
532        }
533    }
534    fn write_r(&mut self, store: &Store, v: u64) {
535        match store {
536            Store::R(i) => self.reg.r[*i] = v,
537            _ => panic!("illegal store to register r"),
538        }
539    }
540    fn read_f(&self, store: &Store) -> m128d {
541        match store {
542            Store::F(i) => self.reg.f[*i],
543            _ => panic!("illegal read from register f"),
544        }
545    }
546    fn write_f(&mut self, store: &Store, v: m128d) {
547        match store {
548            Store::F(i) => self.reg.f[*i] = v,
549            _ => panic!("illegal store to register f"),
550        }
551    }
552
553    fn read_a(&self, store: &Store) -> m128d {
554        match store {
555            Store::A(i) => self.reg.a[*i],
556            _ => panic!("illegal read from register a"),
557        }
558    }
559
560    fn read_e(&self, store: &Store) -> m128d {
561        match store {
562            Store::E(i) => self.reg.e[*i],
563            _ => panic!("illegal read from register e"),
564        }
565    }
566
567    fn write_e(&mut self, store: &Store, v: m128d) {
568        match store {
569            Store::E(i) => self.reg.e[*i] = v,
570            _ => panic!("illegal store to register e"),
571        }
572    }
573    fn scratchpad_src_ix(&self, instr: &Instr) -> usize {
574        let imm = u64_from_i32_imm(instr.imm.unwrap());
575        let addr: usize = match &instr.src {
576            Store::L1(d) => (self.read_r(d).wrapping_add(imm)) & SCRATCHPAD_L1_MASK,
577            Store::L2(d) => (self.read_r(d).wrapping_add(imm)) & SCRATCHPAD_L2_MASK,
578            Store::L3(_) => imm & SCRATCHPAD_L3_MASK,
579            _ => panic!("illegal read from scratchpad"),
580        }
581        .try_into()
582        .unwrap();
583        addr / 8
584    }
585
586    fn scratchpad_dst_ix(&self, instr: &Instr) -> usize {
587        let imm = u64_from_i32_imm(instr.imm.unwrap());
588        let addr: usize = match &instr.dst {
589            Store::L1(d) => (self.read_r(d).wrapping_add(imm)) & SCRATCHPAD_L1_MASK,
590            Store::L2(d) => (self.read_r(d).wrapping_add(imm)) & SCRATCHPAD_L2_MASK,
591            Store::L3(d) => (self.read_r(d).wrapping_add(imm)) & SCRATCHPAD_L3_MASK,
592            _ => panic!("illegal read from scratchpad"),
593        }
594        .try_into()
595        .unwrap();
596        addr / 8
597    }
598
599    fn mask_register_exponent_mantissa(&self, v: m128d) -> m128d {
600        let mantissa_mask = m128d::from_u64(DYNAMIC_MANTISSA_MASK, DYNAMIC_MANTISSA_MASK);
601        let exponent_mask = m128d::from_u64(self.config.e_mask[1], self.config.e_mask[0]);
602        (v & mantissa_mask) | exponent_mask
603    }
604}
605
606pub fn hash_to_m128i_array(hash: &Hash) -> [m128i; 4] {
607    let bytes = hash.as_bytes();
608    let i1 = m128i::from_u8(&bytes[0..16]);
609    let i2 = m128i::from_u8(&bytes[16..32]);
610    let i3 = m128i::from_u8(&bytes[32..48]);
611    let i4 = m128i::from_u8(&bytes[48..64]);
612    [i1, i2, i3, i4]
613}
614
615fn shift_mode(instr: &Instr) -> u8 {
616    match instr.mode {
617        Mode::Shft(x) => x,
618        _ => panic!("illegal shift mode {}", instr.mode),
619    }
620}
621
622fn cond_mode(instr: &Instr) -> u8 {
623    match instr.mode {
624        Mode::Cond(x) => x,
625        _ => panic!("illegal cond mode {}", instr.mode),
626    }
627}
628
629pub fn is_zero_or_power_of_2(imm: u64) -> bool {
630    imm & imm.wrapping_sub(1) == 0
631}
632
633fn small_positive_float_bit(entropy: u64) -> u64 {
634    let mut exponent = entropy >> 59; //0..31
635    let mantissa = entropy & MANTISSA_MASK;
636    exponent += EXPONENT_BIAS;
637    exponent &= EXPONENT_MASK;
638    exponent <<= MANTISSA_SIZE;
639    exponent | mantissa
640}
641
642fn float_mask(entropy: u64) -> u64 {
643    let mask22bit = (1 << 22) - 1;
644    entropy & mask22bit | static_exponent(entropy)
645}
646
647fn static_exponent(entropy: u64) -> u64 {
648    let mut exponent = EXPONENT_BITS;
649    exponent |= (entropy >> (64 - STATIC_EXPONENT_BITS)) << DYNAMIC_EXPONENT_BITS;
650    exponent << MANTISSA_SIZE
651}
652
653pub fn new_vm(mem: Arc<VmMemory>) -> Vm {
654    Vm {
655        mem_reg: MemoryRegister { mx: 0, ma: 0 },
656        reg: new_register(),
657        scratchpad: vec![0; SCRATCHPAD_SIZE],
658        pc: 0,
659        config: VmConfig {
660            e_mask: [0; 2],
661            read_reg: [0; 4],
662        },
663        mem,
664        dataset_offset: 0,
665        mxcsr: MXCSR_DEFAULT,
666    }
667}