1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use crate::{GeneralPurposeRegister};

/// using for 64-bit mode.
pub struct REXPrefix {
    /// related with operand-size.
    pub w_bit: bool,
    /// related with reg-field in ModR/M
    pub r_bit: bool,
    /// related with index-field in ModR/M
    pub x_bit: bool,
    /// related with r/m-field in ModR/M, base in SIB-byte, reg-field in opcode
    pub b_bit: bool,
}

impl REXPrefix {
    pub const BASE: u8 = 0x40;
    pub const W_BIT: u8 = 0x08;
    pub const R_BIT: u8 = 0x04;
    pub const X_BIT: u8 = 0x02;
    pub const B_BIT: u8 = 0x01;


    pub fn to_byte(&self) -> u8 {
        let base = Self::BASE;
        let f = |bit: bool, byte: u8| -> u8{
            if bit {
                byte
            } else {
                0b0
            }
        };

        base | f(self.w_bit, Self::W_BIT) | f(self.r_bit, Self::W_BIT) | f(self.x_bit, Self::X_BIT) | f(self.b_bit, Self::B_BIT)
    }

    pub fn b_bit_from_reg(reg: &GeneralPurposeRegister) -> u8 {
        if reg.is_expanded() {
            Self::B_BIT
        } else {
            0b0
        }
    }
    pub fn r_bit_from_reg(reg: &GeneralPurposeRegister) -> u8 {
        if reg.is_expanded() {
            Self::R_BIT
        } else {
            0b0
        }
    }
}

#[cfg(test)]
mod rex_prefix_tests {
    use crate::REXPrefix;

    #[test]
    fn to_byte_test() {
        let prefix = REXPrefix {
            w_bit: true,
            r_bit: false,
            x_bit: true,
            b_bit: false,
        };

        assert_eq!(REXPrefix::BASE | REXPrefix::W_BIT | REXPrefix::X_BIT, prefix.to_byte());
    }
}