diff options
author | iximeow <me@iximeow.net> | 2020-07-27 01:13:58 -0700 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2020-08-09 01:32:53 -0700 |
commit | 8f9cb0010ad933e308ab66bbac1caa712b6fed6b (patch) | |
tree | 57bdb433d9c2948ec577d7cd34e997e5ee6628e6 | |
parent | fdfec2663a2861f033145018ce1478981c16708b (diff) |
change it all around
add `OperandCodeBuilder` to help manage allocation of enum variant
values, since bit patterns of `OperandCode` are very load-bearing for
decoding
-rw-r--r-- | src/long_mode/mod.rs | 680 |
1 files changed, 489 insertions, 191 deletions
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 35e9c60..5f594ad 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -3182,27 +3182,186 @@ impl PrefixRex { } } +#[derive(Debug)] +struct OperandCodeBuilder { + bits: u16 +} + +#[allow(non_camel_case_types)] +enum ZOperandCategory { + Zv_R = 0, + Zv_AX = 1, + Zb_Ib_R = 2, + Zv_Ivq_R = 3, +} + +struct ZOperandInstructions { + bits: u16 +} + +impl ZOperandInstructions { + fn category(&self) -> u8 { + (self.bits >> 4) as u8 & 0b11 + } + fn reg(&self) -> u8 { + (self.bits & 0b111) as u8 + } +} + +struct EmbeddedOperandInstructions { + bits: u16 +} + +impl EmbeddedOperandInstructions { + fn bits(&self) -> u16 { + self.bits + } +} + +impl OperandCodeBuilder { + const fn new() -> Self { + OperandCodeBuilder { bits: 0 } + } + + const fn bits(&self) -> u16 { + self.bits + } + + const fn from_bits(bits: u16) -> Self { + Self { bits } + } + + const fn read_modrm(mut self) -> Self { + self.bits |= 0x8000; + self + } + + const fn op0_is_rrr_and_embedded_instructions(mut self) -> Self { + self = self.set_embedded_instructions(); + self.bits |= 0x2000; + self + } + + const fn set_embedded_instructions(mut self) -> Self { + self.bits |= 0x4000; + self + } + + fn op0_is_rrr(&self) -> bool { + self.bits & 0x2000 != 0 + } + + fn has_embedded_instructions(&self) -> bool { + self.bits & 0x4000 != 0 + } + + fn get_embedded_instructions(&self) -> Result<ZOperandInstructions, EmbeddedOperandInstructions> { + // 0x4000 indicates embedded instructions + // 0x3fff > 0x0080 indicates the embedded instructions are a Z-style operand + if self.bits & 0x7f80 <= 0x407f { + Ok(ZOperandInstructions { bits: self.bits }) + } else { + Err(EmbeddedOperandInstructions { bits: self.bits }) + } + } + + fn special_case_handler_index(&self) -> u16 { + self.bits & 0x1ff + } + + const fn special_case(mut self, case: u16) -> Self { + // leave 0x4000 unset + self.bits |= case & 0x1ff; + self + } + + const fn operand_case(mut self, case: u16) -> Self { + // leave 0x4000 unset + self.bits |= case & 0xff; + self + } + + const fn op0_is_rrr_and_Z_operand(mut self, category: ZOperandCategory, reg_num: u8) -> Self { + self = self.set_embedded_instructions(); + // if op0 is rrr, 0x2000 unset indicates the operand category written in bits 11:10 + // further, reg number is bits 0:2 + // + // when 0x2000 is unset: + // 0x1cf8 are all unused bits, so far + // + // if you're counting, that's 8 bits remaining. + // it also means one of those (0x0400?) can be used to pick some other interpretation + // scheme. + self.bits |= (category as u8 as u16) << 4; + self.bits |= reg_num as u16 & 0b111; + self + } + + const fn read_E(mut self) -> Self { + self.bits |= 0x1000; + self + } + + const fn has_read_E(&self) -> bool { + self.bits & 0x1000 != 0 + } + + const fn byte_operands(mut self) -> Self { + self.bits |= 0x0800; + self + } + + const fn mem_reg(mut self) -> Self { + self.bits |= 0x0400; + self + } + + const fn reg_mem(self) -> Self { + // 0x0400 unset + self + } + + const fn has_byte_operands(&self) -> bool { + (self.bits & 0x0800) != 0 + } + + const fn has_mem_reg(&self) -> bool { + (self.bits & 0x0400) != 0 + } + + const fn has_reg_mem(&self) -> bool { + (self.bits & 0x0400) == 0 + } + + const fn only_modrm_operands(mut self) -> Self { + self.bits |= 0x0200; + self + } + + const fn is_only_modrm_operands(&self) -> bool { + self.bits & 0x0200 != 0 + } +} + #[allow(non_camel_case_types)] // might be able to pack these into a u8, but with `Operand` being u16 as well now there's little // point. table entries will have a padding byte per record already. // // many of the one-off per-opcode variants could be written as 'decide based on opcode' but trying // to pack this more tightly only makes sense if opcode were smaller, to get some space savings. +// +// bit 15 is "read modrm?" +// 0bMxxx_xxxx_xxxx_xxxx +// | +// | +// | +// | +// | +// | +// ---------------------------> read modr/m? #[repr(u16)] #[derive(Copy, Clone, Debug, PartialEq)] pub enum OperandCode { - ModRM_0x0f00, - ModRM_0x0f01, - ModRM_0x0f0d, - ModRM_0x0fae, - ModRM_0x0fba, - ModRM_0xf238, - ModRM_0xf30fae, - ModRM_0x660fae, - ModRM_0xf30fc7, - ModRM_0x660f38, - ModRM_0xf30f38, - ModRM_0x660f3a, CVT_AA, CVT_DA, Rq_Cq_0, @@ -3218,7 +3377,6 @@ pub enum OperandCode { AH, AX_Xv, // DX_AX, - E_G_xmm, // Ev_Ivs, Ew_Sw, Fw, @@ -3236,25 +3394,171 @@ pub enum OperandCode { Yb_Xb, Yv_AX, Yv_Xv, - G_E_q, + G_E_q = 0x8b00, E_G_q, - G_mm_Ew_Ib, + G_mm_Ew_Ib = 0x8c00, Mq_Dq, - ModRM_0x0f38, - ModRM_0x0f3a, - ModRM_0x0f71, - ModRM_0x0f72, - ModRM_0x0f73, - ModRM_0x660f12, - ModRM_0x660f16, - ModRM_0x660f71, - ModRM_0x660f72, - ModRM_0x660f73, - ModRM_0x660fc7, - ModRM_0x0fc7, Nothing, // Implied, Unsupported, + ModRM_0x0f00 = OperandCodeBuilder::new().read_modrm().special_case(0).bits(), + ModRM_0x0f01 = OperandCodeBuilder::new().read_modrm().special_case(1).bits(), + ModRM_0x0f0d = OperandCodeBuilder::new().read_modrm().special_case(2).bits(), + ModRM_0x0fae = OperandCodeBuilder::new().read_modrm().special_case(3).bits(), + ModRM_0x0fba = OperandCodeBuilder::new().read_modrm().special_case(4).bits(), + ModRM_0xf238 = OperandCodeBuilder::new().read_modrm().special_case(5).bits(), + ModRM_0xf30fae = OperandCodeBuilder::new().read_modrm().special_case(6).bits(), + ModRM_0x660fae = OperandCodeBuilder::new().read_modrm().special_case(7).bits(), + ModRM_0xf30fc7 = OperandCodeBuilder::new().read_modrm().special_case(8).bits(), + ModRM_0x660f38 = OperandCodeBuilder::new().read_modrm().special_case(9).bits(), + ModRM_0xf30f38 = OperandCodeBuilder::new().read_modrm().special_case(10).bits(), + ModRM_0x660f3a = OperandCodeBuilder::new().read_modrm().special_case(11).bits(), + ModRM_0x0f38 = OperandCodeBuilder::new().read_modrm().special_case(12).bits(), + ModRM_0x0f3a = OperandCodeBuilder::new().read_modrm().special_case(13).bits(), + ModRM_0x0f71 = OperandCodeBuilder::new().read_modrm().special_case(14).bits(), + ModRM_0x0f72 = OperandCodeBuilder::new().read_modrm().special_case(15).bits(), + ModRM_0x0f73 = OperandCodeBuilder::new().read_modrm().special_case(16).bits(), + ModRM_0x660f12 = OperandCodeBuilder::new().read_modrm().special_case(17).bits(), + ModRM_0x660f16 = OperandCodeBuilder::new().read_modrm().special_case(18).bits(), + ModRM_0x660f71 = OperandCodeBuilder::new().read_modrm().special_case(19).bits(), + ModRM_0x660f72 = OperandCodeBuilder::new().read_modrm().special_case(20).bits(), + ModRM_0x660f73 = OperandCodeBuilder::new().read_modrm().special_case(21).bits(), + ModRM_0x660fc7 = OperandCodeBuilder::new().read_modrm().special_case(22).bits(), + ModRM_0x0fc7 = OperandCodeBuilder::new().read_modrm().special_case(23).bits(), + // xmmword? + ModRM_0x0f12 = OperandCodeBuilder::new() + .read_modrm() + .op0_is_rrr_and_embedded_instructions() + .read_E() + .reg_mem() + .operand_case(0) + .bits(), + // xmmword? + ModRM_0x0f16 = OperandCodeBuilder::new() + .read_modrm() + .op0_is_rrr_and_embedded_instructions() + .read_E() + .reg_mem() + .operand_case(1) + .bits(), + // encode immediates? + ModRM_0xc0_Eb_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(0) + .bits(), + ModRM_0xc1_Ev_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(0) + .bits(), + ModRM_0xd0_Eb_1 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(1) + .bits(), + ModRM_0xd1_Ev_1 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(1) + .bits(), + ModRM_0xd2_Eb_CL = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(2) + .bits(), + ModRM_0xd3_Ev_CL = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(2) + .bits(), + ModRM_0x80_Eb_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(3) + .bits(), + ModRM_0x83_Ev_Ibs = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(3) + .bits(), + // this would be Eb_Ivs, 0x8e + ModRM_0x81_Ev_Ivs = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(4) + .bits(), + ModRM_0xc6_Eb_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(5) + .bits(), + ModRM_0xc7_Ev_Iv = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(5) + .bits(), + ModRM_0xfe_Eb = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(6) + .bits(), + ModRM_0x8f_Ev = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(6) + .bits(), + // gap, 0x94 + ModRM_0xff_Ev = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(7) + .bits(), + ModRM_0x0f18 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(8) + .bits(), + ModRM_0xf6 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(9) + .bits(), + ModRM_0xf7 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(10) + .bits(), + Ev = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(11) + .bits(), AL_Ib = 0x100, AX_Ib = 0x101, Ib_AL = 0x102, @@ -3264,105 +3568,86 @@ pub enum OperandCode { DX_AX = 0x106, DX_AL = 0x107, MOVQ_f30f = 0x108, - G_xmm_Ed_Ib = 0x1ef, // mirror G_xmm_Edq, but also read an immediate - Zv_R0 = 0x40, - Zv_R1 = 0x41, - Zv_R2 = 0x42, - Zv_R3 = 0x43, - Zv_R4 = 0x44, - Zv_R5 = 0x45, - Zv_R6 = 0x46, - Zv_R7 = 0x47, + Zv_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 0).bits(), + Zv_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 1).bits(), + Zv_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 2).bits(), + Zv_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 3).bits(), + Zv_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 4).bits(), + Zv_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 5).bits(), + Zv_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 6).bits(), + Zv_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 7).bits(), // Zv_AX_R0 = 0x48, - Zv_AX_R1 = 0x49, - Zv_AX_R2 = 0x4a, - Zv_AX_R3 = 0x4b, - Zv_AX_R4 = 0x4c, - Zv_AX_R5 = 0x4d, - Zv_AX_R6 = 0x4e, - Zv_AX_R7 = 0x4f, - Zb_Ib_R0 = 0x50, - Zb_Ib_R1 = 0x51, - Zb_Ib_R2 = 0x52, - Zb_Ib_R3 = 0x53, - Zb_Ib_R4 = 0x54, - Zb_Ib_R5 = 0x55, - Zb_Ib_R6 = 0x56, - Zb_Ib_R7 = 0x57, - Zv_Ivq_R0 = 0x58, - Zv_Ivq_R1 = 0x59, - Zv_Ivq_R2 = 0x5a, - Zv_Ivq_R3 = 0x5b, - Zv_Ivq_R4 = 0x5c, - Zv_Ivq_R5 = 0x5d, - Zv_Ivq_R6 = 0x5e, - Zv_Ivq_R7 = 0x5f, - Gv_Eb = 0x60, - Gv_Ew = 0x61, - Gdq_Ed = 0x62, - G_E_mm_Ib = 0x64, - G_E_xmm_Ib = 0x65, - AL_Ibs = 0x66, - AX_Ivd = 0x67, - AL_Ob = 0x68, - AL_Xb = 0x69, - AX_AL = 0x6a, - AX_Ov = 0x6b, - - Eb_Gb = 0x80, - Ev_Gv = 0x81, - Gb_Eb = 0xc2, - Gv_Ev = 0xc3, - Gb_Eb_Ib = 0xc4, - Gv_Ev_Iv = 0xc5, + Zv_AX_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 1).bits(), + Zv_AX_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 2).bits(), + Zv_AX_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 3).bits(), + Zv_AX_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 4).bits(), + Zv_AX_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 5).bits(), + Zv_AX_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 6).bits(), + Zv_AX_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 7).bits(), + Zb_Ib_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 0).bits(), + Zb_Ib_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 1).bits(), + Zb_Ib_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 2).bits(), + Zb_Ib_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 3).bits(), + Zb_Ib_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 4).bits(), + Zb_Ib_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 5).bits(), + Zb_Ib_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 6).bits(), + Zb_Ib_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 7).bits(), + Zv_Ivq_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Ivq_R, 0).bits(), + Zv_Ivq_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Ivq_R, 1).bits(), + Zv_Ivq_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Ivq_R, 2).bits(), + Zv_Ivq_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Ivq_R, 3).bits(), + Zv_Ivq_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Ivq_R, 4).bits(), + Zv_Ivq_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Ivq_R, 5).bits(), + Zv_Ivq_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Ivq_R, 6).bits(), + Zv_Ivq_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Ivq_R, 7).bits(), + Gv_Eb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(4).bits(), + Gv_Ew = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(5).bits(), + Gdq_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(6).bits(), + G_E_mm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(2).bits(), + G_E_xmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(8).bits(), + AL_Ob = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(0).bits(), + AL_Xb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(1).bits(), + AX_AL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(2).bits(), + AX_Ov = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(3).bits(), + AL_Ibs = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().byte_operands().operand_case(0).bits(), + AX_Ivd = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(9).bits(), + + Eb_Gb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().byte_operands().only_modrm_operands().mem_reg().bits(), + Ev_Gv = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().mem_reg().bits(), + Gb_Eb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().byte_operands().only_modrm_operands().reg_mem().bits(), + Gv_Ev = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().reg_mem().bits(), + Gb_Eb_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().byte_operands().reg_mem().operand_case(1).bits(), + Gv_Ev_Iv = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(1).bits(), // gap: 0xc6 - Gd_U_xmm = 0xc7, - Gv_E_xmm = 0x1c7, - M_G_xmm = 0xc9, - ModRM_0x0f12 = 0xcb, - ModRM_0x0f16 = 0xce, - ModRM_0xc0_Eb_Ib = 0x86, - ModRM_0xc1_Ev_Ib = 0x87, - ModRM_0xd0_Eb_1 = 0x88, - ModRM_0xd1_Ev_1 = 0x89, - ModRM_0xd2_Eb_CL = 0x8a, - ModRM_0xd3_Ev_CL = 0x8b, - ModRM_0x80_Eb_Ib = 0x8c, - ModRM_0x83_Ev_Ibs = 0x8d, - // this would be Eb_Ivs, 0x8e - ModRM_0x81_Ev_Ivs = 0x8f, - ModRM_0xc6_Eb_Ib = 0x90, - ModRM_0xc7_Ev_Iv = 0x91, - ModRM_0xfe_Eb = 0x92, - ModRM_0x8f_Ev = 0x93, - // gap, 0x94 - ModRM_0xff_Ev = 0x95, - ModRM_0xf6 = 0x96, - ModRM_0xf7 = 0x97, Eb_R0 = 0x98, - Ev = 0x99, - ModRM_0x0f18 = 0x9b, + Rv_Gmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_modrm().read_E().reg_mem().operand_case(25).bits(), // gap, 0x9a - Gv_M = 0xdb, - G_mm_Edq = 0xdd, - G_mm_E = 0xdf, - G_U_xmm = 0xe1, - G_xmm_Eq = 0xe3, - G_mm_E_xmm = 0xe5, - G_E_mm = 0xe7, - Edq_G_mm = 0xe9, - Edq_G_xmm = 0x1e9, - E_G_mm = 0xeb, - G_xmm_E_mm = 0xed, - G_xmm_U_mm = 0x1ed, - U_mm_G_xmm = 0x2ed, - Rv_Gmm_Ib = 0x3ed, - G_xmm_Edq = 0xef, - G_U_mm = 0xf1, - Ev_Gv_Ib = 0xf3, - Ev_Gv_CL = 0xf5, - G_M_xmm = 0xf7, - G_E_xmm = 0xf9, +// Gv_M = 0xdb, + Gv_M = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().bits(), + G_xmm_E_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(23).bits(), + G_xmm_U_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(24).bits(), + U_mm_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(25).bits(), + G_xmm_Edq = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(26).bits(), + G_xmm_Eq = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(27).bits(), + G_mm_E_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(28).bits(), + Gd_U_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(29).bits(), + Gv_E_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(30).bits(), + //= 0x816f, // mirror G_xmm_Edq, but also read an immediate + G_xmm_Ed_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(31).bits(), + G_U_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(13).bits(), + G_M_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(10).bits(), + G_E_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(9).bits(), + E_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(11).bits(), + M_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(12).bits(), + G_E_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(14).bits(), + G_U_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(15).bits(), + E_G_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(16).bits(), + Edq_G_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(17).bits(), + Edq_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(18).bits(), + G_mm_Edq = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(19).bits(), + G_mm_E = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(20).bits(), + Ev_Gv_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(21).bits(), + Ev_Gv_CL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(22).bits(), } fn base_opcode_map(v: u8) -> Opcode { @@ -5229,68 +5514,85 @@ fn read_instr<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, in Ok(()) } fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, length: &mut u8) -> Result<(), DecodeError> { - if (operand_code as u8) & 0x40 == 0x40 { - instruction.operands[0] = OperandSpec::RegRRR; - } - if (operand_code as u8) >= 0x40 && (operand_code as u8) < 0x60 { - let reg = (operand_code as u8) & 0x07; - let category = ((operand_code as u8) & 0x18) >> 3; - if category == 0 { - // these are Zv_R - let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes); - let bank = if opwidth == 4 { - RegisterBank::D - } else if opwidth == 2 { - RegisterBank::W - } else { - RegisterBank::Q - }; - instruction.modrm_rrr = - RegSpec::from_parts(reg, instruction.prefixes.rex().b(), bank); - instruction.operand_count = 1; - // Zv_AX are missing! - } else if category == 2 { - // these are Zb_Ib_R - instruction.modrm_rrr = - RegSpec::gp_from_parts(reg, instruction.prefixes.rex().b(), 1, instruction.prefixes.rex().present()); - instruction.imm = - read_imm_unsigned(&mut bytes_iter, 1, length)?; - instruction.operands[1] = OperandSpec::ImmU8; - instruction.operand_count = 2; - } else { - // category == 3, Zv_Ivq_R - let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); - let bank = if opwidth == 4 { - RegisterBank::D - } else if opwidth == 2 { - RegisterBank::W - } else { - RegisterBank::Q - }; - instruction.modrm_rrr = - RegSpec::from_parts(reg, instruction.prefixes.rex().b(), bank); - instruction.imm = - read_imm_ivq(&mut bytes_iter, opwidth, length)?; - instruction.operands[1] = match opwidth { - 1 => OperandSpec::ImmI8, - 2 => OperandSpec::ImmI16, - 4 => OperandSpec::ImmI32, - 8 => OperandSpec::ImmI64, - _ => unsafe { unreachable_unchecked() } - }; - instruction.operand_count = 2; + let operand_code = OperandCodeBuilder::from_bits(operand_code as u16); + if operand_code.has_embedded_instructions() { + match operand_code.get_embedded_instructions() { + Ok(z_operand_code) => { + let reg = z_operand_code.reg(); + match z_operand_code.category() { + 0 => { + // these are Zv_R + let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes); + let bank = if opwidth == 4 { + RegisterBank::D + } else if opwidth == 2 { + RegisterBank::W + } else { + RegisterBank::Q + }; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.modrm_rrr = + RegSpec::from_parts(reg, instruction.prefixes.rex().b(), bank); + instruction.operand_count = 1; + } + 1 => { + // Zv_AX + } + 2 => { + // these are Zb_Ib_R + instruction.operands[0] = OperandSpec::RegRRR; + instruction.modrm_rrr = + RegSpec::gp_from_parts(reg, instruction.prefixes.rex().b(), 1, instruction.prefixes.rex().present()); + instruction.imm = + read_imm_unsigned(&mut bytes_iter, 1, length)?; + instruction.operands[1] = OperandSpec::ImmU8; + instruction.operand_count = 2; + } + 3 => { + // category == 3, Zv_Ivq_R + let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let bank = if opwidth == 4 { + RegisterBank::D + } else if opwidth == 2 { + RegisterBank::W + } else { + RegisterBank::Q + }; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.modrm_rrr = + RegSpec::from_parts(reg, instruction.prefixes.rex().b(), bank); + instruction.imm = + read_imm_ivq(&mut bytes_iter, opwidth, length)?; + instruction.operands[1] = match opwidth { + 1 => OperandSpec::ImmI8, + 2 => OperandSpec::ImmI16, + 4 => OperandSpec::ImmI32, + 8 => OperandSpec::ImmI64, + _ => unsafe { unreachable_unchecked() } + }; + instruction.operand_count = 2; + } + _ => { + unreachable!("bad category"); + } + } + return Ok(()); + }, + Err(embedded_operand_instructions) => { + if operand_code.op0_is_rrr() { + instruction.operands[0] = OperandSpec::RegRRR; + } + } } - return Ok(()); } let mut modrm = 0; let mut opwidth = 0; let mut mem_oper = OperandSpec::Nothing; let mut bank = RegisterBank::Q; - let code_int = operand_code as u8; - if ((code_int) & 0x80) == 0x80 { + if operand_code.has_read_E() { // cool! we can precompute opwidth and know we need to read_E. - if (code_int & 1) == 1 { + if !operand_code.has_byte_operands() { // further, this is an vdq E opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); if opwidth == 4 { @@ -5313,9 +5615,8 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, mem_oper = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; } - let numeric_code = (operand_code as u8) & 0xbf; - if numeric_code >= 0x80 && numeric_code < 0x84 { - let (mmm, rrr) = if numeric_code & 0x02 == 2 { + if operand_code.is_only_modrm_operands() { + let (mmm, rrr) = if operand_code.has_reg_mem() { (1, 0) } else { (0, 1) @@ -5323,12 +5624,13 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, instruction.operands[mmm] = mem_oper; instruction.operands[rrr] = OperandSpec::RegRRR; instruction.operand_count = 2; - } else if operand_code == OperandCode::Ibs { + } else if operand_code.bits() == OperandCode::Ibs as u16 { instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u64; instruction.operands[0] = OperandSpec::ImmI8; instruction.operand_count = 1; } else { + let operand_code: OperandCode = unsafe { core::mem::transmute(operand_code.bits()) }; match operand_code { /* Gv_Ev_Iv, @@ -5639,14 +5941,14 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, instruction.operand_count = 2; }, OperandCode::E_G_xmm => { - let modrm = read_modrm(&mut bytes_iter, length)?; - -// println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m); - instruction.operands[0] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?; - instruction.modrm_rrr = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X); + instruction.modrm_rrr.bank = RegisterBank::X; + instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; + if instruction.operands[0] == OperandSpec::RegMMM { + // fix the register to XMM + instruction.modrm_mmm.bank = RegisterBank::X; + } }, OperandCode::G_E_mm => { instruction.operands[1] = mem_oper; @@ -5680,7 +5982,6 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, op @ OperandCode::G_M_xmm | op @ OperandCode::G_E_xmm => { instruction.modrm_rrr.bank = RegisterBank::X; - instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; instruction.operand_count = 2; if instruction.operands[1] == OperandSpec::RegMMM { @@ -5707,10 +6008,7 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, instruction.operand_count = 3; }, OperandCode::G_E_mm_Ib => { - let modrm = read_modrm(&mut bytes_iter, length)?; - -// println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m); - instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?; + instruction.operands[1] = mem_oper; instruction.modrm_rrr = RegSpec { bank: RegisterBank::MM, num: (modrm >> 3) & 7 }; instruction.operands[0] = OperandSpec::RegRRR; instruction.imm = |