Skip to main content

native_v86_core/cpu/
arith.rs

1use crate::cpu::cpu::*;
2use crate::cpu::global_pointers::*;
3use crate::cpu::memory;
4use crate::cpu::misc_instr::{getaf, getcf, getzf};
5
6fn int_log2(x: i32) -> i32 {
7    31 - x.leading_zeros() as i32
8}
9
10fn opsize_to_mask(op_size: i32) -> i32 {
11    dbg_assert!(op_size == OPSIZE_8 || op_size == OPSIZE_16 || op_size == OPSIZE_32);
12    (2i32.wrapping_shl(op_size as u32)).wrapping_sub(1)
13}
14
15unsafe fn add(dest_operand: i32, source_operand: i32, op_size: i32) -> i32 {
16    let res = dest_operand.wrapping_add(source_operand) & opsize_to_mask(op_size);
17    *last_op1 = dest_operand;
18    *last_result = res;
19    *last_op_size = op_size;
20    *flags_changed = FLAGS_ALL;
21    return res;
22}
23unsafe fn adc(dest_operand: i32, source_operand: i32, op_size: i32) -> i32 {
24    let cf = getcf() as i32;
25    let res = dest_operand.wrapping_add(source_operand).wrapping_add(cf) & opsize_to_mask(op_size);
26    *last_op1 = dest_operand;
27    *last_result = res;
28    *last_op_size = op_size;
29    *flags_changed = FLAGS_ALL & !FLAG_CARRY & !FLAG_ADJUST & !FLAG_OVERFLOW;
30    *flags = *flags & !FLAG_CARRY & !FLAG_ADJUST & !FLAG_OVERFLOW
31        | (dest_operand ^ ((dest_operand ^ source_operand) & (source_operand ^ res))) >> op_size
32            & FLAG_CARRY
33        | (dest_operand ^ source_operand ^ res) & FLAG_ADJUST
34        | ((source_operand ^ res) & (dest_operand ^ res)) >> op_size << 11 & FLAG_OVERFLOW;
35    return res;
36}
37unsafe fn sub(dest_operand: i32, source_operand: i32, op_size: i32) -> i32 {
38    let res = dest_operand.wrapping_sub(source_operand) & opsize_to_mask(op_size);
39    *last_op1 = dest_operand;
40    *last_result = res;
41    *last_op_size = op_size;
42    *flags_changed = FLAGS_ALL | FLAG_SUB;
43    return res;
44}
45unsafe fn sbb(dest_operand: i32, source_operand: i32, op_size: i32) -> i32 {
46    let cf = getcf() as i32;
47    let res = dest_operand.wrapping_sub(source_operand).wrapping_sub(cf) & opsize_to_mask(op_size);
48    *last_op1 = dest_operand;
49    *last_result = res;
50    *last_op_size = op_size;
51    *flags_changed = FLAGS_ALL & !FLAG_CARRY & !FLAG_ADJUST & !FLAG_OVERFLOW | FLAG_SUB;
52    *flags = *flags & !FLAG_CARRY & !FLAG_ADJUST & !FLAG_OVERFLOW
53        | (res ^ ((res ^ source_operand) & (source_operand ^ dest_operand))) >> op_size
54            & FLAG_CARRY
55        | (dest_operand ^ source_operand ^ res) & FLAG_ADJUST
56        | ((source_operand ^ dest_operand) & (res ^ dest_operand)) >> op_size << 11 & FLAG_OVERFLOW;
57    return res;
58}
59pub unsafe fn add8(x: i32, y: i32) -> i32 {
60    dbg_assert!(x >= 0 && x < 0x100);
61    dbg_assert!(y >= 0 && y < 0x100);
62    return add(x, y, OPSIZE_8);
63}
64#[no_mangle]
65pub unsafe fn add16(x: i32, y: i32) -> i32 {
66    dbg_assert!(x >= 0 && x < 0x10000);
67    dbg_assert!(y >= 0 && y < 0x10000);
68    return add(x, y, OPSIZE_16);
69}
70pub unsafe fn add32(x: i32, y: i32) -> i32 {
71    return add(x, y, OPSIZE_32);
72}
73pub unsafe fn sub8(x: i32, y: i32) -> i32 {
74    return sub(x, y, OPSIZE_8);
75}
76#[no_mangle]
77pub unsafe fn sub16(x: i32, y: i32) -> i32 {
78    return sub(x, y, OPSIZE_16);
79}
80pub unsafe fn sub32(x: i32, y: i32) -> i32 {
81    return sub(x, y, OPSIZE_32);
82}
83#[no_mangle]
84pub unsafe fn adc8(x: i32, y: i32) -> i32 {
85    return adc(x, y, OPSIZE_8);
86}
87#[no_mangle]
88pub unsafe fn adc16(x: i32, y: i32) -> i32 {
89    return adc(x, y, OPSIZE_16);
90}
91pub unsafe fn adc32(x: i32, y: i32) -> i32 {
92    return adc(x, y, OPSIZE_32);
93}
94#[no_mangle]
95pub unsafe fn sbb8(x: i32, y: i32) -> i32 {
96    return sbb(x, y, OPSIZE_8);
97}
98#[no_mangle]
99pub unsafe fn sbb16(x: i32, y: i32) -> i32 {
100    return sbb(x, y, OPSIZE_16);
101}
102pub unsafe fn sbb32(x: i32, y: i32) -> i32 {
103    return sbb(x, y, OPSIZE_32);
104}
105pub unsafe fn cmp8(x: i32, y: i32) {
106    dbg_assert!(x >= 0 && x < 0x100);
107    dbg_assert!(y >= 0 && y < 0x100);
108    sub(x, y, OPSIZE_8);
109}
110pub unsafe fn cmp16(x: i32, y: i32) {
111    dbg_assert!(x >= 0 && x < 0x10000);
112    dbg_assert!(y >= 0 && y < 0x10000);
113    sub(x, y, OPSIZE_16);
114}
115pub unsafe fn cmp32(x: i32, y: i32) {
116    sub(x, y, OPSIZE_32);
117}
118unsafe fn inc(dest_operand: i32, op_size: i32) -> i32 {
119    *flags = *flags & !1 | getcf() as i32;
120    let res = (dest_operand + 1) & opsize_to_mask(op_size);
121    *last_op1 = dest_operand;
122    *last_result = res;
123    *last_op_size = op_size;
124    *flags_changed = FLAGS_ALL & !1;
125    return res;
126}
127unsafe fn dec(dest_operand: i32, op_size: i32) -> i32 {
128    *flags = *flags & !1 | getcf() as i32;
129    let res = (dest_operand - 1) & opsize_to_mask(op_size);
130    *last_op1 = dest_operand;
131    *last_result = res;
132    *last_op_size = op_size;
133    *flags_changed = FLAGS_ALL & !1 | FLAG_SUB;
134    return res;
135}
136#[no_mangle]
137pub unsafe fn inc8(x: i32) -> i32 {
138    return inc(x, OPSIZE_8);
139}
140pub unsafe fn inc16(x: i32) -> i32 {
141    return inc(x, OPSIZE_16);
142}
143pub unsafe fn inc32(x: i32) -> i32 {
144    return inc(x, OPSIZE_32);
145}
146#[no_mangle]
147pub unsafe fn dec8(x: i32) -> i32 {
148    return dec(x, OPSIZE_8);
149}
150pub unsafe fn dec16(x: i32) -> i32 {
151    return dec(x, OPSIZE_16);
152}
153pub unsafe fn dec32(x: i32) -> i32 {
154    return dec(x, OPSIZE_32);
155}
156
157unsafe fn neg(dest_operand: i32, op_size: i32) -> i32 {
158    sub(0, dest_operand, op_size)
159}
160#[no_mangle]
161pub unsafe fn not8(x: i32) -> i32 {
162    return !x;
163}
164#[no_mangle]
165pub unsafe fn neg8(x: i32) -> i32 {
166    return neg(x, OPSIZE_8);
167}
168#[no_mangle]
169pub unsafe fn neg16(x: i32) -> i32 {
170    return neg(x, OPSIZE_16);
171}
172pub unsafe fn neg32(x: i32) -> i32 {
173    return neg(x, OPSIZE_32);
174}
175
176#[no_mangle]
177pub unsafe fn mul8(source_operand: i32) {
178    let result = source_operand * read_reg8(AL);
179    write_reg16(AX, result);
180    *last_result = result & 255;
181    *last_op_size = OPSIZE_8;
182    if result < 256 {
183        *flags &= !1 & !FLAG_OVERFLOW
184    } else {
185        *flags |= 1 | FLAG_OVERFLOW
186    }
187    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
188}
189#[no_mangle]
190pub unsafe fn imul8(source_operand: i32) {
191    let result = source_operand * (read_reg8(AL) << 24 >> 24);
192    write_reg16(AX, result);
193    *last_result = result & 255;
194    *last_op_size = OPSIZE_8;
195    if result > 127 || result < -128 {
196        *flags |= 1 | FLAG_OVERFLOW
197    } else {
198        *flags &= !1 & !FLAG_OVERFLOW
199    }
200    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
201}
202#[no_mangle]
203pub unsafe fn mul16(source_operand: u32) {
204    let result = source_operand * read_reg16(AX) as u32;
205    let high_result = result >> 16;
206    write_reg16(AX, result as i32);
207    write_reg16(DX, high_result as i32);
208    *last_result = (result & 0xFFFF) as i32;
209    *last_op_size = OPSIZE_16;
210    if high_result == 0 {
211        *flags &= !1 & !FLAG_OVERFLOW
212    } else {
213        *flags |= 1 | FLAG_OVERFLOW
214    }
215    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
216}
217#[no_mangle]
218pub unsafe fn imul16(source_operand: i32) {
219    let result = source_operand * (read_reg16(AX) << 16 >> 16);
220    write_reg16(AX, result);
221    write_reg16(DX, result >> 16);
222    *last_result = result & 0xFFFF;
223    *last_op_size = OPSIZE_16;
224    if result > 32767 || result < -32768 {
225        *flags |= 1 | FLAG_OVERFLOW
226    } else {
227        *flags &= !1 & !FLAG_OVERFLOW
228    }
229    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
230}
231#[no_mangle]
232pub unsafe fn imul_reg16(mut operand1: i32, mut operand2: i32) -> i32 {
233    operand1 = operand1 << 16 >> 16;
234    operand2 = operand2 << 16 >> 16;
235    let result = operand1 * operand2;
236    *last_result = result & 0xFFFF;
237    *last_op_size = OPSIZE_16;
238    if result > 32767 || result < -32768 {
239        *flags |= 1 | FLAG_OVERFLOW
240    } else {
241        *flags &= !1 & !FLAG_OVERFLOW
242    }
243    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
244    return result;
245}
246#[no_mangle]
247pub unsafe fn mul32(source_operand: i32) {
248    let dest_operand = read_reg32(EAX);
249    let result = (dest_operand as u32 as u64) * (source_operand as u32 as u64);
250    let result_low = result as i32;
251    let result_high = (result >> 32) as i32;
252    write_reg32(EAX, result_low);
253    write_reg32(EDX, result_high);
254    *last_result = result_low;
255    *last_op_size = OPSIZE_32;
256    if result_high == 0 {
257        *flags &= !1 & !FLAG_OVERFLOW
258    } else {
259        *flags |= 1 | FLAG_OVERFLOW
260    }
261    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
262}
263pub unsafe fn imul32(source_operand: i32) {
264    let dest_operand = read_reg32(EAX);
265    let result = dest_operand as i64 * source_operand as i64;
266    let result_low = result as i32;
267    let result_high = (result >> 32) as i32;
268    write_reg32(EAX, result_low);
269    write_reg32(EDX, result_high);
270    *last_result = result_low;
271    *last_op_size = OPSIZE_32;
272    if result_high == result_low >> 31 {
273        *flags &= !1 & !FLAG_OVERFLOW
274    } else {
275        *flags |= 1 | FLAG_OVERFLOW
276    }
277    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
278}
279pub unsafe fn imul_reg32(operand1: i32, operand2: i32) -> i32 {
280    let result = operand1 as i64 * operand2 as i64;
281    let result_low = result as i32;
282    let result_high = (result >> 32) as i32;
283    *last_result = result_low;
284    *last_op_size = OPSIZE_32;
285    if result_high == result_low >> 31 {
286        *flags &= !1 & !FLAG_OVERFLOW
287    } else {
288        *flags |= 1 | FLAG_OVERFLOW
289    }
290    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
291    return result_low;
292}
293
294#[no_mangle]
295pub unsafe fn xadd8(source_operand: i32, reg: i32) -> i32 {
296    let tmp = read_reg8(reg);
297    write_reg8(reg, source_operand);
298    return add(source_operand, tmp, OPSIZE_8);
299}
300#[no_mangle]
301pub unsafe fn xadd16(source_operand: i32, reg: i32) -> i32 {
302    let tmp = read_reg16(reg);
303    write_reg16(reg, source_operand);
304    return add(source_operand, tmp, OPSIZE_16);
305}
306pub unsafe fn xadd32(source_operand: i32, reg: i32) -> i32 {
307    let tmp = read_reg32(reg);
308    write_reg32(reg, source_operand);
309    return add(source_operand, tmp, OPSIZE_32);
310}
311
312#[no_mangle]
313pub unsafe fn cmpxchg8(data: i32, r: i32) -> i32 {
314    cmp8(read_reg8(AL), data);
315    if getzf() {
316        read_reg8(r)
317    } else {
318        write_reg8(AL, data);
319        data
320    }
321}
322#[no_mangle]
323pub unsafe fn cmpxchg16(data: i32, r: i32) -> i32 {
324    cmp16(read_reg16(AX), data);
325    if getzf() {
326        read_reg16(r)
327    } else {
328        write_reg16(AX, data);
329        data
330    }
331}
332pub unsafe fn cmpxchg32(data: i32, r: i32) -> i32 {
333    cmp32(read_reg32(EAX), data);
334    if getzf() {
335        read_reg32(r)
336    } else {
337        write_reg32(EAX, data);
338        data
339    }
340}
341
342#[no_mangle]
343pub unsafe fn bcd_daa() {
344    let old_al = read_reg8(AL);
345    let old_cf = getcf();
346    let old_af = getaf();
347    *flags &= !1 & !FLAG_ADJUST;
348    if old_al & 15 > 9 || old_af {
349        write_reg8(AL, read_reg8(AL) + 6);
350        *flags |= FLAG_ADJUST
351    }
352    if old_al > 153 || old_cf {
353        write_reg8(AL, read_reg8(AL) + 96);
354        *flags |= 1
355    }
356    *last_result = read_reg8(AL);
357    *last_op_size = OPSIZE_8;
358    *flags_changed = FLAGS_ALL & !1 & !FLAG_ADJUST & !FLAG_OVERFLOW;
359}
360#[no_mangle]
361pub unsafe fn bcd_das() {
362    let old_al = read_reg8(AL);
363    let old_cf = getcf();
364    *flags &= !1;
365    if old_al & 15 > 9 || getaf() {
366        write_reg8(AL, read_reg8(AL) - 6);
367        *flags |= FLAG_ADJUST;
368        *flags = *flags & !1 | old_cf as i32 | (old_al < 6) as i32
369    } else {
370        *flags &= !FLAG_ADJUST
371    }
372    if old_al > 153 || old_cf {
373        write_reg8(AL, read_reg8(AL) - 96);
374        *flags |= 1
375    }
376    *last_result = read_reg8(AL);
377    *last_op_size = OPSIZE_8;
378    *flags_changed = FLAGS_ALL & !1 & !FLAG_ADJUST & !FLAG_OVERFLOW;
379}
380#[no_mangle]
381pub unsafe fn bcd_aad(imm8: i32) {
382    let result = read_reg8(AL) + read_reg8(AH) * imm8;
383    *last_result = result & 255;
384    write_reg16(AX, *last_result);
385    *last_op_size = OPSIZE_8;
386    *flags_changed = FLAGS_ALL & !1 & !FLAG_ADJUST & !FLAG_OVERFLOW;
387    *flags &= !1 & !FLAG_ADJUST & !FLAG_OVERFLOW;
388    if result > 0xFFFF {
389        *flags |= 1
390    };
391}
392#[no_mangle]
393pub unsafe fn bcd_aam(imm8: i32) {
394    // ascii adjust after multiplication
395    if imm8 == 0 {
396        trigger_de();
397    } else {
398        let temp = read_reg8(AL);
399        write_reg8(AH, temp as i32 / imm8);
400        write_reg8(AL, temp as i32 % imm8);
401        *last_result = read_reg8(AL);
402        *last_op_size = OPSIZE_8;
403        *flags_changed = FLAGS_ALL & !1 & !FLAG_ADJUST & !FLAG_OVERFLOW;
404        *flags &= !1 & !FLAG_ADJUST & !FLAG_OVERFLOW
405    };
406}
407#[no_mangle]
408pub unsafe fn bcd_aaa() {
409    if read_reg8(AL) & 15 > 9 || getaf() {
410        write_reg16(AX, read_reg16(AX) + 6);
411        write_reg8(AH, read_reg8(AH) + 1);
412        *flags |= FLAG_ADJUST | 1
413    } else {
414        *flags &= !FLAG_ADJUST & !1
415    }
416    write_reg8(AL, read_reg8(AL) & 15);
417    *flags_changed &= !FLAG_ADJUST & !1;
418}
419#[no_mangle]
420pub unsafe fn bcd_aas() {
421    if read_reg8(AL) & 15 > 9 || getaf() {
422        write_reg16(AX, read_reg16(AX) - 6);
423        write_reg8(AH, read_reg8(AH) - 1);
424        *flags |= FLAG_ADJUST | 1
425    } else {
426        *flags &= !FLAG_ADJUST & !1
427    }
428    write_reg8(AL, read_reg8(AL) & 15);
429    *flags_changed &= !FLAG_ADJUST & !1;
430}
431unsafe fn and(dest_operand: i32, source_operand: i32, op_size: i32) -> i32 {
432    let result = dest_operand & source_operand;
433    *last_result = result;
434    *last_op_size = op_size;
435    *flags &= !1 & !FLAG_OVERFLOW & !FLAG_ADJUST;
436    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW & !FLAG_ADJUST;
437    return result;
438}
439unsafe fn or(dest_operand: i32, source_operand: i32, op_size: i32) -> i32 {
440    let result = dest_operand | source_operand;
441    *last_result = result;
442    *last_op_size = op_size;
443    *flags &= !1 & !FLAG_OVERFLOW & !FLAG_ADJUST;
444    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW & !FLAG_ADJUST;
445    return result;
446}
447unsafe fn xor(dest_operand: i32, source_operand: i32, op_size: i32) -> i32 {
448    let result = dest_operand ^ source_operand;
449    *last_result = result;
450    *last_op_size = op_size;
451    *flags &= !1 & !FLAG_OVERFLOW & !FLAG_ADJUST;
452    *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW & !FLAG_ADJUST;
453    return result;
454}
455pub unsafe fn and8(x: i32, y: i32) -> i32 {
456    return and(x, y, OPSIZE_8);
457}
458#[no_mangle]
459pub unsafe fn and16(x: i32, y: i32) -> i32 {
460    return and(x, y, OPSIZE_16);
461}
462pub unsafe fn and32(x: i32, y: i32) -> i32 {
463    return and(x, y, OPSIZE_32);
464}
465pub unsafe fn test8(x: i32, y: i32) {
466    and(x, y, OPSIZE_8);
467}
468pub unsafe fn test16(x: i32, y: i32) {
469    and(x, y, OPSIZE_16);
470}
471pub unsafe fn test32(x: i32, y: i32) {
472    and(x, y, OPSIZE_32);
473}
474pub unsafe fn or8(x: i32, y: i32) -> i32 {
475    return or(x, y, OPSIZE_8);
476}
477#[no_mangle]
478pub unsafe fn or16(x: i32, y: i32) -> i32 {
479    return or(x, y, OPSIZE_16);
480}
481pub unsafe fn or32(x: i32, y: i32) -> i32 {
482    return or(x, y, OPSIZE_32);
483}
484pub unsafe fn xor8(x: i32, y: i32) -> i32 {
485    return xor(x, y, OPSIZE_8);
486}
487#[no_mangle]
488pub unsafe fn xor16(x: i32, y: i32) -> i32 {
489    return xor(x, y, OPSIZE_16);
490}
491pub unsafe fn xor32(x: i32, y: i32) -> i32 {
492    return xor(x, y, OPSIZE_32);
493}
494
495#[no_mangle]
496pub unsafe fn rol8(dest_operand: i32, mut count: i32) -> i32 {
497    dbg_assert!(count >= 0 && count < 32);
498    if 0 == count {
499        return dest_operand;
500    } else {
501        count &= 7;
502        let result = dest_operand << count | dest_operand >> 8 - count;
503        *flags_changed &= !1 & !FLAG_OVERFLOW;
504        *flags = *flags & !1 & !FLAG_OVERFLOW
505            | result & 1
506            | (result << 11 ^ result << 4) & FLAG_OVERFLOW;
507        return result & 0xFF;
508    };
509}
510#[no_mangle]
511pub unsafe fn rol16(dest_operand: i32, mut count: i32) -> i32 {
512    dbg_assert!(count >= 0 && count < 32);
513    if 0 == count {
514        return dest_operand;
515    } else {
516        count &= 15;
517        let result = dest_operand << count | dest_operand >> 16 - count;
518        *flags_changed &= !1 & !FLAG_OVERFLOW;
519        *flags = *flags & !1 & !FLAG_OVERFLOW
520            | result & 1
521            | (result << 11 ^ result >> 4) & FLAG_OVERFLOW;
522        return result & 0xFFFF;
523    };
524}
525#[no_mangle]
526pub unsafe fn rol32(dest_operand: i32, count: i32) -> i32 {
527    dbg_assert!(count >= 0 && count < 32);
528    if 0 == count {
529        return dest_operand;
530    } else {
531        let result = ((dest_operand << count) as u32 | dest_operand as u32 >> 32 - count) as i32;
532        *flags_changed &= !1 & !FLAG_OVERFLOW;
533        *flags = *flags & !1 & !FLAG_OVERFLOW
534            | result & 1
535            | (result << 11 ^ result >> 20) & FLAG_OVERFLOW;
536        return result;
537    };
538}
539#[no_mangle]
540pub unsafe fn rcl8(dest_operand: i32, mut count: i32) -> i32 {
541    dbg_assert!(count >= 0 && count < 32);
542    count %= 9;
543    if 0 == count {
544        return dest_operand;
545    } else {
546        let result =
547            dest_operand << count | (getcf() as i32) << count - 1 | dest_operand >> 9 - count;
548        *flags_changed &= !1 & !FLAG_OVERFLOW;
549        *flags = *flags & !1 & !FLAG_OVERFLOW
550            | result >> 8 & 1
551            | (result << 3 ^ result << 4) & FLAG_OVERFLOW;
552        return result & 0xFF;
553    };
554}
555#[no_mangle]
556pub unsafe fn rcl16(dest_operand: i32, mut count: i32) -> i32 {
557    dbg_assert!(count >= 0 && count < 32);
558    count %= 17;
559    if 0 == count {
560        return dest_operand;
561    } else {
562        let result =
563            dest_operand << count | (getcf() as i32) << count - 1 | dest_operand >> 17 - count;
564        *flags_changed &= !1 & !FLAG_OVERFLOW;
565        *flags = *flags & !1 & !FLAG_OVERFLOW
566            | result >> 16 & 1
567            | (result >> 5 ^ result >> 4) & FLAG_OVERFLOW;
568        return result & 0xFFFF;
569    };
570}
571#[no_mangle]
572pub unsafe fn rcl32(dest_operand: i32, count: i32) -> i32 {
573    dbg_assert!(count >= 0 && count < 32);
574    if 0 == count {
575        return dest_operand;
576    } else {
577        let mut result = dest_operand << count | (getcf() as i32) << count - 1;
578        if count > 1 {
579            result = (result as u32 | dest_operand as u32 >> 33 - count) as i32
580        }
581        *flags_changed &= !1 & !FLAG_OVERFLOW;
582        let b = (dest_operand as u32 >> 32 - count & 1) as i32;
583        *flags = (*flags & !1 & !FLAG_OVERFLOW | b) | (b << 11 ^ result >> 20) & FLAG_OVERFLOW;
584        return result;
585    };
586}
587#[no_mangle]
588pub unsafe fn ror8(dest_operand: i32, mut count: i32) -> i32 {
589    dbg_assert!(count >= 0 && count < 32);
590    if 0 == count {
591        return dest_operand;
592    } else {
593        count &= 7;
594        let result = dest_operand >> count | dest_operand << 8 - count;
595        *flags_changed &= !1 & !FLAG_OVERFLOW;
596        *flags = *flags & !1 & !FLAG_OVERFLOW
597            | result >> 7 & 1
598            | (result << 4 ^ result << 5) & FLAG_OVERFLOW;
599        return result & 0xFF;
600    };
601}
602#[no_mangle]
603pub unsafe fn ror16(dest_operand: i32, mut count: i32) -> i32 {
604    dbg_assert!(count >= 0 && count < 32);
605    if 0 == count {
606        return dest_operand;
607    } else {
608        count &= 15;
609        let result = dest_operand >> count | dest_operand << 16 - count;
610        *flags_changed &= !1 & !FLAG_OVERFLOW;
611        *flags = *flags & !1 & !FLAG_OVERFLOW
612            | result >> 15 & 1
613            | (result >> 4 ^ result >> 3) & FLAG_OVERFLOW;
614        return result & 0xFFFF;
615    };
616}
617#[no_mangle]
618pub unsafe fn ror32(dest_operand: i32, count: i32) -> i32 {
619    dbg_assert!(count >= 0 && count < 32);
620    if 0 == count {
621        return dest_operand;
622    } else {
623        let result = (dest_operand as u32 >> count | (dest_operand << 32 - count) as u32) as i32;
624        *flags_changed &= !1 & !FLAG_OVERFLOW;
625        *flags = *flags & !1 & !FLAG_OVERFLOW
626            | result >> 31 & 1
627            | (result >> 20 ^ result >> 19) & FLAG_OVERFLOW;
628        return result;
629    };
630}
631#[no_mangle]
632pub unsafe fn rcr8(dest_operand: i32, mut count: i32) -> i32 {
633    dbg_assert!(count >= 0 && count < 32);
634    count %= 9;
635    if 0 == count {
636        return dest_operand;
637    } else {
638        let result =
639            dest_operand >> count | (getcf() as i32) << 8 - count | dest_operand << 9 - count;
640        *flags_changed &= !1 & !FLAG_OVERFLOW;
641        *flags = *flags & !1 & !FLAG_OVERFLOW
642            | result >> 8 & 1
643            | (result << 4 ^ result << 5) & FLAG_OVERFLOW;
644        return result & 0xFF;
645    };
646}
647#[no_mangle]
648pub unsafe fn rcr16(dest_operand: i32, mut count: i32) -> i32 {
649    dbg_assert!(count >= 0 && count < 32);
650    count %= 17;
651    if 0 == count {
652        return dest_operand;
653    } else {
654        let result =
655            dest_operand >> count | (getcf() as i32) << 16 - count | dest_operand << 17 - count;
656        *flags_changed &= !1 & !FLAG_OVERFLOW;
657        *flags = *flags & !1 & !FLAG_OVERFLOW
658            | result >> 16 & 1
659            | (result >> 4 ^ result >> 3) & FLAG_OVERFLOW;
660        return result & 0xFFFF;
661    };
662}
663#[no_mangle]
664pub unsafe fn rcr32(dest_operand: i32, count: i32) -> i32 {
665    dbg_assert!(count >= 0 && count < 32);
666    if 0 == count {
667        return dest_operand;
668    } else {
669        let mut result =
670            (dest_operand as u32 >> count | ((getcf() as i32) << 32 - count) as u32) as i32;
671        if count > 1 {
672            result |= dest_operand << 33 - count
673        }
674        *flags_changed &= !1 & !FLAG_OVERFLOW;
675        *flags = *flags & !1 & !FLAG_OVERFLOW
676            | dest_operand >> count - 1 & 1
677            | (result >> 20 ^ result >> 19) & FLAG_OVERFLOW;
678        return result;
679    };
680}
681#[no_mangle]
682pub unsafe fn div8(source_operand: u32) {
683    if source_operand == 0 {
684        trigger_de();
685        return;
686    }
687    let target_operand = read_reg16(AX) as u32;
688    let result = target_operand / source_operand;
689    if result >= 0x100 {
690        trigger_de();
691        return;
692    }
693    write_reg8(AL, result as i32);
694    write_reg8(AH, (target_operand % source_operand) as i32);
695}
696
697#[no_mangle]
698pub unsafe fn idiv8(source_operand: i32) {
699    if source_operand == 0 {
700        trigger_de();
701        return;
702    }
703    let target_operand = read_reg16(AX) << 16 >> 16;
704    let result = target_operand / source_operand;
705    if result >= 0x80 || result < -0x80 {
706        trigger_de();
707        return;
708    }
709    write_reg8(AL, result);
710    write_reg8(AH, target_operand % source_operand);
711}
712
713#[no_mangle]
714pub unsafe fn div16_without_fault(source_operand: u32) -> bool {
715    let target_operand = (read_reg16(AX) | read_reg16(DX) << 16) as u32;
716    let result = match target_operand.checked_div(source_operand) {
717        None => return false,
718        Some(r) => r,
719    };
720    if result >= 0x10000 {
721        return false;
722    }
723    write_reg16(AX, result as i32);
724    write_reg16(DX, (target_operand % source_operand) as i32);
725    return true;
726}
727pub unsafe fn div16(source_operand: u32) {
728    if !div16_without_fault(source_operand) {
729        trigger_de()
730    }
731}
732#[no_mangle]
733pub unsafe fn idiv16_without_fault(source_operand: i32) -> bool {
734    let target_operand = read_reg16(AX) | read_reg16(DX) << 16;
735    let result = match target_operand.checked_div(source_operand) {
736        None => return false,
737        Some(r) => r,
738    };
739    if result >= 0x8000 || result < -0x8000 {
740        return false;
741    }
742    write_reg16(AX, result);
743    write_reg16(DX, (target_operand % source_operand) as i32);
744    return true;
745}
746pub unsafe fn idiv16(source_operand: i32) {
747    if !idiv16_without_fault(source_operand) {
748        trigger_de()
749    }
750}
751
752pub unsafe fn div32_without_fault(source_operand: u32) -> bool {
753    let source_operand = source_operand as u64;
754    let target_low = read_reg32(EAX) as u32;
755    let target_high = read_reg32(EDX) as u32;
756    let target_operand = (target_high as u64) << 32 | target_low as u64;
757    let result = match target_operand.checked_div(source_operand) {
758        None => return false,
759        Some(r) => r,
760    };
761    if result > 0xFFFFFFFF {
762        return false;
763    }
764    let modulo = target_operand % source_operand;
765    write_reg32(EAX, result as i32);
766    write_reg32(EDX, modulo as i32);
767    return true;
768}
769pub unsafe fn div32(source_operand: u32) {
770    if !div32_without_fault(source_operand) {
771        trigger_de()
772    }
773}
774#[no_mangle]
775pub unsafe fn idiv32_without_fault(source_operand: i32) -> bool {
776    let source_operand = source_operand as i64;
777    let target_low = read_reg32(EAX) as u32;
778    let target_high = read_reg32(EDX) as u32;
779    let target_operand = (target_high as i64) << 32 | target_low as i64;
780    let result = match target_operand.checked_div(source_operand) {
781        None => return false,
782        Some(r) => r,
783    };
784    if result < -0x80000000 || result > 0x7FFFFFFF {
785        return false;
786    }
787    let modulo = target_operand % source_operand;
788    write_reg32(EAX, result as i32);
789    write_reg32(EDX, modulo as i32);
790    return true;
791}
792pub unsafe fn idiv32(source_operand: i32) {
793    if !idiv32_without_fault(source_operand) {
794        trigger_de()
795    }
796}
797
798#[no_mangle]
799pub unsafe fn shl8(dest_operand: i32, count: i32) -> i32 {
800    dbg_assert!(count >= 0 && count < 32);
801    if count == 0 {
802        return dest_operand;
803    } else {
804        let result = dest_operand << count;
805        *last_result = result;
806        *last_op_size = OPSIZE_8;
807        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
808        *flags = *flags & !1 & !FLAG_OVERFLOW
809            | result >> 8 & 1
810            | (result << 3 ^ result << 4) & FLAG_OVERFLOW;
811        return result & 0xFF;
812    };
813}
814#[no_mangle]
815pub unsafe fn shl16(dest_operand: i32, count: i32) -> i32 {
816    dbg_assert!(count >= 0 && count < 32);
817    if count == 0 {
818        return dest_operand;
819    } else {
820        let result = dest_operand << count;
821        *last_result = result;
822        *last_op_size = OPSIZE_16;
823        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
824        *flags = *flags & !1 & !FLAG_OVERFLOW
825            | result >> 16 & 1
826            | (result >> 5 ^ result >> 4) & FLAG_OVERFLOW;
827        return result & 0xFFFF;
828    };
829}
830pub unsafe fn shl32(dest_operand: i32, count: i32) -> i32 {
831    dbg_assert!(count >= 0 && count < 32);
832    if count == 0 {
833        return dest_operand;
834    } else {
835        let result = dest_operand << count;
836        *last_result = result;
837        *last_op_size = OPSIZE_32;
838        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
839        let b = dest_operand >> 32 - count & 1;
840        *flags = *flags & !1 & !FLAG_OVERFLOW | b | (b ^ result >> 31) << 11 & FLAG_OVERFLOW;
841        return result;
842    };
843}
844#[no_mangle]
845pub unsafe fn shr8(dest_operand: i32, count: i32) -> i32 {
846    dbg_assert!(count >= 0 && count < 32);
847    if count == 0 {
848        return dest_operand;
849    } else {
850        let result = dest_operand >> count;
851        *last_result = result;
852        *last_op_size = OPSIZE_8;
853        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
854        *flags = *flags & !1 & !FLAG_OVERFLOW
855            | dest_operand >> count - 1 & 1
856            | (dest_operand >> 7 & 1) << 11 & FLAG_OVERFLOW;
857        return result;
858    };
859}
860#[no_mangle]
861pub unsafe fn shr16(dest_operand: i32, count: i32) -> i32 {
862    dbg_assert!(count >= 0 && count < 32);
863    if count == 0 {
864        return dest_operand;
865    } else {
866        let result = dest_operand >> count;
867        *last_result = result;
868        *last_op_size = OPSIZE_16;
869        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
870        *flags = *flags & !1 & !FLAG_OVERFLOW
871            | dest_operand >> count - 1 & 1
872            | dest_operand >> 4 & FLAG_OVERFLOW;
873        return result;
874    };
875}
876pub unsafe fn shr32(dest_operand: i32, count: i32) -> i32 {
877    dbg_assert!(count >= 0 && count < 32);
878    if count == 0 {
879        return dest_operand;
880    } else {
881        let result = (dest_operand as u32 >> count) as i32;
882        *last_result = result;
883        *last_op_size = OPSIZE_32;
884        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
885        *flags = (*flags & !1 & !FLAG_OVERFLOW)
886            | (dest_operand as u32 >> count - 1 & 1) as i32
887            | (dest_operand >> 20 & FLAG_OVERFLOW);
888        return result;
889    };
890}
891#[no_mangle]
892pub unsafe fn sar8(dest_operand: i32, count: i32) -> i32 {
893    dbg_assert!(count >= 0 && count < 32);
894    if count == 0 {
895        return dest_operand;
896    } else {
897        let result;
898        if count < 8 {
899            result = dest_operand << 24 >> count + 24;
900            // of is zero
901            *flags = *flags & !1 & !FLAG_OVERFLOW | dest_operand >> count - 1 & 1
902        } else {
903            result = dest_operand << 24 >> 31;
904            *flags = *flags & !1 & !FLAG_OVERFLOW | result & 1
905        }
906        *last_result = result;
907        *last_op_size = OPSIZE_8;
908        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
909        return result & 0xFF;
910    };
911}
912#[no_mangle]
913pub unsafe fn sar16(dest_operand: i32, count: i32) -> i32 {
914    dbg_assert!(count >= 0 && count < 32);
915    if count == 0 {
916        return dest_operand;
917    } else {
918        let result;
919        if count < 16 {
920            result = dest_operand << 16 >> count + 16;
921            *flags = *flags & !1 & !FLAG_OVERFLOW | dest_operand >> count - 1 & 1
922        } else {
923            result = dest_operand << 16 >> 31;
924            *flags = *flags & !1 & !FLAG_OVERFLOW | result & 1
925        }
926        *last_result = result;
927        *last_op_size = OPSIZE_16;
928        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
929        return result & 0xFFFF;
930    };
931}
932pub unsafe fn sar32(dest_operand: i32, count: i32) -> i32 {
933    dbg_assert!(count >= 0 && count < 32);
934    if count == 0 {
935        return dest_operand;
936    } else {
937        let result = dest_operand >> count;
938        *last_result = result;
939        *last_op_size = OPSIZE_32;
940        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
941        *flags = (*flags & !1 & !FLAG_OVERFLOW) | (dest_operand as u32 >> count - 1 & 1) as i32;
942        return result;
943    };
944}
945
946#[no_mangle]
947pub unsafe fn shrd16(dest_operand: i32, source_operand: i32, count: i32) -> i32 {
948    dbg_assert!(count >= 0 && count < 32);
949    if count == 0 {
950        return dest_operand;
951    } else {
952        let result;
953        if count <= 16 {
954            result = dest_operand >> count | source_operand << 16 - count;
955            *flags = *flags & !1 | dest_operand >> count - 1 & 1
956        } else {
957            result = dest_operand << 32 - count | source_operand >> count - 16;
958            *flags = *flags & !1 | source_operand >> count - 17 & 1
959        }
960        *last_result = result;
961        *last_op_size = OPSIZE_16;
962        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
963        *flags = *flags & !FLAG_OVERFLOW | (result ^ dest_operand) >> 4 & FLAG_OVERFLOW;
964        return result & 0xFFFF;
965    };
966}
967#[no_mangle]
968pub unsafe fn shrd32(dest_operand: i32, source_operand: i32, count: i32) -> i32 {
969    dbg_assert!(count >= 0 && count < 32);
970    if count == 0 {
971        return dest_operand;
972    } else {
973        let result = (dest_operand as u32 >> count | (source_operand << 32 - count) as u32) as i32;
974        *last_result = result;
975        *last_op_size = OPSIZE_32;
976        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
977        *flags = ((*flags & !1 & !FLAG_OVERFLOW) | (dest_operand as u32 >> count - 1 & 1) as i32)
978            | (result ^ dest_operand) >> 20 & FLAG_OVERFLOW;
979        return result;
980    };
981}
982#[no_mangle]
983pub unsafe fn shld16(dest_operand: i32, source_operand: i32, count: i32) -> i32 {
984    dbg_assert!(count >= 0 && count < 32);
985    if count == 0 {
986        return dest_operand;
987    } else {
988        let result;
989        if count <= 16 {
990            result = ((dest_operand << count) as u32 | source_operand as u32 >> 16 - count) as i32;
991            *flags = (*flags & !1) | (dest_operand as u32 >> 16 - count & 1) as i32;
992        } else {
993            result = dest_operand >> 32 - count | source_operand << count - 16;
994            *flags = (*flags & !1) | (source_operand as u32 >> 32 - count & 1) as i32;
995        }
996        *last_result = result;
997        *last_op_size = OPSIZE_16;
998        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
999        *flags = *flags & !FLAG_OVERFLOW | (*flags & 1 ^ result >> 15 & 1) << 11;
1000        return result & 0xFFFF;
1001    };
1002}
1003#[no_mangle]
1004pub unsafe fn shld32(dest_operand: i32, source_operand: i32, count: i32) -> i32 {
1005    dbg_assert!(count >= 0 && count < 32);
1006    if count == 0 {
1007        return dest_operand;
1008    } else {
1009        let result = ((dest_operand << count) as u32 | source_operand as u32 >> 32 - count) as i32;
1010        *last_result = result;
1011        *last_op_size = OPSIZE_32;
1012        *flags_changed = FLAGS_ALL & !1 & !FLAG_OVERFLOW;
1013        *flags = (*flags & !1) | (dest_operand as u32 >> 32 - count & 1) as i32;
1014        if count == 1 {
1015            *flags = *flags & !FLAG_OVERFLOW | (*flags & 1 ^ result >> 31 & 1) << 11
1016        } else {
1017            *flags &= !FLAG_OVERFLOW
1018        }
1019        return result;
1020    };
1021}
1022
1023pub unsafe fn bt_reg(bit_base: i32, bit_offset: i32) {
1024    *flags = *flags & !1 | bit_base >> bit_offset & 1;
1025    *flags_changed &= !1;
1026}
1027pub unsafe fn btc_reg(bit_base: i32, bit_offset: i32) -> i32 {
1028    *flags = *flags & !1 | bit_base >> bit_offset & 1;
1029    *flags_changed &= !1;
1030    return bit_base ^ 1 << bit_offset;
1031}
1032pub unsafe fn bts_reg(bit_base: i32, bit_offset: i32) -> i32 {
1033    *flags = *flags & !1 | bit_base >> bit_offset & 1;
1034    *flags_changed &= !1;
1035    return bit_base | 1 << bit_offset;
1036}
1037pub unsafe fn btr_reg(bit_base: i32, bit_offset: i32) -> i32 {
1038    *flags = *flags & !1 | bit_base >> bit_offset & 1;
1039    *flags_changed &= !1;
1040    return bit_base & !(1 << bit_offset);
1041}
1042
1043pub unsafe fn bt_mem(virt_addr: i32, mut bit_offset: i32) {
1044    let bit_base = return_on_pagefault!(safe_read8(virt_addr + (bit_offset >> 3)));
1045    bit_offset &= 7;
1046    *flags = *flags & !1 | bit_base >> bit_offset & 1;
1047    *flags_changed &= !1;
1048}
1049pub unsafe fn btc_mem(virt_addr: i32, mut bit_offset: i32) {
1050    let phys_addr = return_on_pagefault!(translate_address_write(virt_addr + (bit_offset >> 3)));
1051    let bit_base = memory::read8(phys_addr);
1052    bit_offset &= 7;
1053    *flags = *flags & !1 | bit_base >> bit_offset & 1;
1054    *flags_changed &= !1;
1055    memory::write8(phys_addr, bit_base ^ 1 << bit_offset);
1056}
1057pub unsafe fn btr_mem(virt_addr: i32, mut bit_offset: i32) {
1058    let phys_addr = return_on_pagefault!(translate_address_write(virt_addr + (bit_offset >> 3)));
1059    let bit_base = memory::read8(phys_addr);
1060    bit_offset &= 7;
1061    *flags = *flags & !1 | bit_base >> bit_offset & 1;
1062    *flags_changed &= !1;
1063    memory::write8(phys_addr, bit_base & !(1 << bit_offset));
1064}
1065pub unsafe fn bts_mem(virt_addr: i32, mut bit_offset: i32) {
1066    let phys_addr = return_on_pagefault!(translate_address_write(virt_addr + (bit_offset >> 3)));
1067    let bit_base = memory::read8(phys_addr);
1068    bit_offset &= 7;
1069    *flags = *flags & !1 | bit_base >> bit_offset & 1;
1070    *flags_changed &= !1;
1071    memory::write8(phys_addr, bit_base | 1 << bit_offset);
1072}
1073
1074#[no_mangle]
1075pub unsafe fn bsf16(old: i32, bit_base: i32) -> i32 {
1076    *flags_changed = FLAGS_ALL & !FLAG_ZERO & !FLAG_CARRY;
1077    *flags &= !FLAG_CARRY;
1078    *last_op_size = OPSIZE_16;
1079    if bit_base == 0 {
1080        *flags |= FLAG_ZERO;
1081        *last_result = bit_base;
1082        // not defined in the docs, but value doesn't change on my intel machine
1083        return old;
1084    } else {
1085        *flags &= !FLAG_ZERO;
1086        *last_result = int_log2(bit_base.wrapping_neg() & bit_base);
1087        return *last_result;
1088    };
1089}
1090#[no_mangle]
1091pub unsafe fn bsf32(old: i32, bit_base: i32) -> i32 {
1092    *flags_changed = FLAGS_ALL & !FLAG_ZERO & !FLAG_CARRY;
1093    *flags &= !FLAG_CARRY;
1094    *last_op_size = OPSIZE_32;
1095    if bit_base == 0 {
1096        *flags |= FLAG_ZERO;
1097        *last_result = bit_base;
1098        return old;
1099    } else {
1100        *flags &= !FLAG_ZERO;
1101        *last_result = int_log2(bit_base.wrapping_neg() & bit_base);
1102        return *last_result;
1103    };
1104}
1105#[no_mangle]
1106pub unsafe fn bsr16(old: i32, bit_base: i32) -> i32 {
1107    *flags_changed = FLAGS_ALL & !FLAG_ZERO & !FLAG_CARRY;
1108    *flags &= !FLAG_CARRY;
1109    *last_op_size = OPSIZE_16;
1110    if bit_base == 0 {
1111        *flags |= FLAG_ZERO;
1112        *last_result = bit_base;
1113        return old;
1114    } else {
1115        *flags &= !FLAG_ZERO;
1116        *last_result = int_log2(bit_base);
1117        return *last_result;
1118    };
1119}
1120#[no_mangle]
1121pub unsafe fn bsr32(old: i32, bit_base: i32) -> i32 {
1122    *flags_changed = FLAGS_ALL & !FLAG_ZERO & !FLAG_CARRY;
1123    *flags &= !FLAG_CARRY;
1124    *last_op_size = OPSIZE_32;
1125    if bit_base == 0 {
1126        *flags |= FLAG_ZERO;
1127        *last_result = bit_base;
1128        return old;
1129    } else {
1130        *flags &= !FLAG_ZERO;
1131        *last_result = int_log2(bit_base);
1132        return *last_result;
1133    };
1134}
1135#[no_mangle]
1136pub unsafe fn popcnt(v: i32) -> i32 {
1137    *flags_changed = 0;
1138    *flags &= !FLAGS_ALL;
1139    if 0 != v {
1140        return v.count_ones() as i32;
1141    } else {
1142        *flags |= FLAG_ZERO;
1143        return 0;
1144    };
1145}
1146
1147pub unsafe fn saturate_sw_to_ub(v: u16) -> u8 {
1148    let mut ret = v;
1149    if ret >= 32768 {
1150        ret = 0
1151    } else if ret > 255 {
1152        ret = 255
1153    }
1154    return ret as u8;
1155}
1156pub unsafe fn saturate_sw_to_sb(v: i32) -> u8 {
1157    dbg_assert!(v as u32 & 0xFFFF_0000 == 0);
1158    let mut ret = v;
1159    if ret > 65408 {
1160        ret = ret & 255
1161    } else if ret > 32767 {
1162        ret = 128
1163    } else if ret > 127 {
1164        ret = 127
1165    }
1166    dbg_assert!(ret as u32 & 0xFFFF_FF00 == 0);
1167    return ret as u8;
1168}
1169pub unsafe fn saturate_sd_to_sw(v: u32) -> u16 {
1170    let mut ret = v;
1171    if ret > 4294934528 {
1172        ret = ret & 0xFFFF
1173    } else if ret > 0x7FFFFFFF {
1174        ret = 32768
1175    } else if ret > 32767 {
1176        ret = 32767
1177    }
1178    dbg_assert!(ret & 0xFFFF_0000 == 0);
1179    return ret as u16;
1180}
1181pub unsafe fn saturate_sd_to_sb(v: u32) -> i8 {
1182    let mut ret = v;
1183    if ret > 0xFFFFFF80 {
1184        ret = ret & 255
1185    } else if ret > 0x7FFFFFFF {
1186        ret = 128
1187    } else if ret > 127 {
1188        ret = 127
1189    }
1190    dbg_assert!(ret & 0xFFFF_FF00 == 0);
1191    return ret as i8;
1192}
1193pub unsafe fn saturate_sd_to_ub(v: i32) -> i32 {
1194    let mut ret = v;
1195    if ret < 0 {
1196        ret = 0
1197    }
1198    dbg_assert!(ret as u32 & 0xFFFF_FF00 == 0);
1199    return ret;
1200}
1201pub unsafe fn saturate_ud_to_ub(v: u32) -> u8 {
1202    let mut ret = v;
1203    if ret > 255 {
1204        ret = 255
1205    }
1206    dbg_assert!(ret & 0xFFFF_FF00 == 0);
1207    return ret as u8;
1208}
1209pub unsafe fn saturate_uw(v: u32) -> u16 {
1210    let mut ret = v;
1211    if ret > 0x7FFFFFFF {
1212        ret = 0
1213    } else if ret > 0xFFFF {
1214        ret = 0xFFFF
1215    }
1216    dbg_assert!(ret & 0xFFFF_0000 == 0);
1217    return ret as u16;
1218}