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, 2 => 0b01, 3 => 0b11, _ => 0b00, };
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 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 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 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 } }
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 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 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; 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}