| ... | @@ -206,19 +206,22 @@ pub const Instruction = struct { | ... | @@ -206,19 +206,22 @@ pub const Instruction = struct { |
| 206 | }; | 206 | }; |
| 207 | } | 207 | } |
| 208 | | 208 | |
| 209 | pub fn isBaseExtended(op: Operand) bool { | 209 | pub fn baseExtEnc(op: Operand) u2 { |
| 210 | return switch (op) { | 210 | return switch (op) { |
| 211 | .none, .imm => false, | 211 | .none, .imm => 0b00, |
| 212 | .reg => |reg| reg.isExtended(), | 212 | .reg => |reg| @truncate(reg.enc() >> 3), |
| 213 | .mem => |mem| mem.base().isExtended(), | 213 | .mem => |mem| switch (mem.base()) { |
| | 214 | .none, .frame, .table, .reloc, .rip_inst => 0b00, // rsp, rbp, and rip are not extended |
| | 215 | .reg => |reg| @truncate(reg.enc() >> 3), |
| | 216 | }, |
| 214 | .bytes => unreachable, | 217 | .bytes => unreachable, |
| 215 | }; | 218 | }; |
| 216 | } | 219 | } |
| 217 | | 220 | |
| 218 | pub fn isIndexExtended(op: Operand) bool { | 221 | pub fn indexExtEnc(op: Operand) u2 { |
| 219 | return switch (op) { | 222 | return switch (op) { |
| 220 | .none, .reg, .imm => false, | 223 | .none, .reg, .imm => 0b00, |
| 221 | .mem => |mem| if (mem.scaleIndex()) |si| si.index.isExtended() else false, | 224 | .mem => |mem| if (mem.scaleIndex()) |si| @truncate(si.index.enc() >> 3) else 0b00, |
| 222 | .bytes => unreachable, | 225 | .bytes => unreachable, |
| 223 | }; | 226 | }; |
| 224 | } | 227 | } |
| ... | @@ -422,14 +425,14 @@ pub const Instruction = struct { | ... | @@ -422,14 +425,14 @@ pub const Instruction = struct { |
| 422 | }; | 425 | }; |
| 423 | switch (mem_op) { | 426 | switch (mem_op) { |
| 424 | .reg => |reg| { | 427 | .reg => |reg| { |
| 425 | const rm = switch (data.op_en) { | 428 | const rm: u3 = switch (data.op_en) { |
| 426 | .ia, .m, .mi, .m1, .mc, .vm, .vmi => enc.modRmExt(), | 429 | .ia, .m, .mi, .m1, .mc, .vm, .vmi => enc.modRmExt(), |
| 427 | .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(), | 430 | .mr, .mri, .mrc => @truncate(inst.ops[1].reg.enc()), |
| 428 | .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => inst.ops[0].reg.lowEnc(), | 431 | .rm, .rmi, .rm0, .rvm, .rvmr, .rvmi, .rmv => @truncate(inst.ops[0].reg.enc()), |
| 429 | .mvr => inst.ops[2].reg.lowEnc(), | 432 | .mvr => @truncate(inst.ops[2].reg.enc()), |
| 430 | else => unreachable, | 433 | else => unreachable, |
| 431 | }; | 434 | }; |
| 432 | try encoder.modRm_direct(rm, reg.lowEnc()); | 435 | try encoder.modRm_direct(rm, @truncate(reg.enc())); |
| 433 | }, | 436 | }, |
| 434 | .mem => |mem| { | 437 | .mem => |mem| { |
| 435 | const op = switch (data.op_en) { | 438 | const op = switch (data.op_en) { |
| ... | @@ -448,7 +451,7 @@ pub const Instruction = struct { | ... | @@ -448,7 +451,7 @@ pub const Instruction = struct { |
| 448 | .ia => try encodeImm(inst.ops[0].imm, data.ops[0], encoder), | 451 | .ia => try encodeImm(inst.ops[0].imm, data.ops[0], encoder), |
| 449 | .mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder), | 452 | .mi => try encodeImm(inst.ops[1].imm, data.ops[1], encoder), |
| 450 | .rmi, .mri, .vmi => try encodeImm(inst.ops[2].imm, data.ops[2], encoder), | 453 | .rmi, .mri, .vmi => try encodeImm(inst.ops[2].imm, data.ops[2], encoder), |
| 451 | .rvmr => try encoder.imm8(@as(u8, inst.ops[3].reg.enc()) << 4), | 454 | .rvmr => try encoder.imm8(@as(u8, @as(u4, @intCast(inst.ops[3].reg.enc()))) << 4), |
| 452 | .rvmi => try encodeImm(inst.ops[3].imm, data.ops[3], encoder), | 455 | .rvmi => try encodeImm(inst.ops[3].imm, data.ops[3], encoder), |
| 453 | else => {}, | 456 | else => {}, |
| 454 | } | 457 | } |
| ... | @@ -462,8 +465,8 @@ pub const Instruction = struct { | ... | @@ -462,8 +465,8 @@ pub const Instruction = struct { |
| 462 | const final = opcode.len - 1; | 465 | const final = opcode.len - 1; |
| 463 | for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte); | 466 | for (opcode[first..final]) |byte| try encoder.opcode_1byte(byte); |
| 464 | switch (inst.encoding.data.op_en) { | 467 | switch (inst.encoding.data.op_en) { |
| 465 | .o, .oz, .oi => try encoder.opcode_withReg(opcode[final], inst.ops[0].reg.lowEnc()), | 468 | .o, .oz, .oi => try encoder.opcode_withReg(opcode[final], @truncate(inst.ops[0].reg.enc())), |
| 466 | .zo => try encoder.opcode_withReg(opcode[final], inst.ops[1].reg.lowEnc()), | 469 | .zo => try encoder.opcode_withReg(opcode[final], @truncate(inst.ops[1].reg.enc())), |
| 467 | else => try encoder.opcode_1byte(opcode[final]), | 470 | else => try encoder.opcode_1byte(opcode[final]), |
| 468 | } | 471 | } |
| 469 | } | 472 | } |
| ... | @@ -533,23 +536,29 @@ pub const Instruction = struct { | ... | @@ -533,23 +536,29 @@ pub const Instruction = struct { |
| 533 | | 536 | |
| 534 | switch (op_en) { | 537 | switch (op_en) { |
| 535 | .z, .i, .zi, .ii, .ia, .fd, .td, .d => {}, | 538 | .z, .i, .zi, .ii, .ia, .fd, .td, .d => {}, |
| 536 | .o, .oz, .oi => rex.b = inst.ops[0].reg.isExtended(), | 539 | .o, .oz, .oi => rex.b = inst.ops[0].reg.enc() & 0b01000 != 0, |
| 537 | .zo => rex.b = inst.ops[1].reg.isExtended(), | 540 | .zo => rex.b = inst.ops[1].reg.enc() & 0b01000 != 0, |
| 538 | .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .rmv => { | 541 | .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .rm0, .rmv => { |
| 539 | const r_op = switch (op_en) { | 542 | const r_op = switch (op_en) { |
| 540 | .rm, .rmi, .rm0, .rmv => inst.ops[0], | 543 | .rm, .rmi, .rm0, .rmv => inst.ops[0], |
| 541 | .mr, .mri, .mrc => inst.ops[1], | 544 | .mr, .mri, .mrc => inst.ops[1], |
| 542 | else => .none, | 545 | else => .none, |
| 543 | }; | 546 | }; |
| 544 | rex.r = r_op.isBaseExtended(); | 547 | const r_op_base_ext_enc = r_op.baseExtEnc(); |
| | 548 | rex.r = r_op_base_ext_enc & 0b01 != 0; |
| | 549 | assert(r_op_base_ext_enc & 0b10 == 0); |
| 545 | | 550 | |
| 546 | const b_x_op = switch (op_en) { | 551 | const b_x_op = switch (op_en) { |
| 547 | .rm, .rmi, .rm0 => inst.ops[1], | 552 | .rm, .rmi, .rm0 => inst.ops[1], |
| 548 | .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0], | 553 | .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0], |
| 549 | else => unreachable, | 554 | else => unreachable, |
| 550 | }; | 555 | }; |
| 551 | rex.b = b_x_op.isBaseExtended(); | 556 | const b_x_op_base_ext_enc = b_x_op.baseExtEnc(); |
| 552 | rex.x = b_x_op.isIndexExtended(); | 557 | rex.b = b_x_op_base_ext_enc & 0b01 != 0; |
| | 558 | assert(b_x_op_base_ext_enc & 0b10 == 0); |
| | 559 | const b_x_op_index_ext_enc = b_x_op.indexExtEnc(); |
| | 560 | rex.x = b_x_op_index_ext_enc & 0b01 != 0; |
| | 561 | assert(b_x_op_index_ext_enc & 0b10 == 0); |
| 553 | }, | 562 | }, |
| 554 | .vm, .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable, | 563 | .vm, .vmi, .rvm, .rvmr, .rvmi, .mvr => unreachable, |
| 555 | } | 564 | } |
| ... | @@ -576,7 +585,9 @@ pub const Instruction = struct { | ... | @@ -576,7 +585,9 @@ pub const Instruction = struct { |
| 576 | .m, .mi, .m1, .mc, .vm, .vmi => .none, | 585 | .m, .mi, .m1, .mc, .vm, .vmi => .none, |
| 577 | else => unreachable, | 586 | else => unreachable, |
| 578 | }; | 587 | }; |
| 579 | vex.r = r_op.isBaseExtended(); | 588 | const r_op_base_ext_enc = r_op.baseExtEnc(); |
| | 589 | vex.r = r_op_base_ext_enc & 0b01 != 0; |
| | 590 | assert(r_op_base_ext_enc & 0b10 == 0); |
| 580 | | 591 | |
| 581 | const b_x_op = switch (op_en) { | 592 | const b_x_op = switch (op_en) { |
| 582 | .rm, .rmi, .rm0, .vm, .vmi, .rmv => inst.ops[1], | 593 | .rm, .rmi, .rm0, .vm, .vmi, .rmv => inst.ops[1], |
| ... | @@ -584,8 +595,12 @@ pub const Instruction = struct { | ... | @@ -584,8 +595,12 @@ pub const Instruction = struct { |
| 584 | .rvm, .rvmr, .rvmi => inst.ops[2], | 595 | .rvm, .rvmr, .rvmi => inst.ops[2], |
| 585 | else => unreachable, | 596 | else => unreachable, |
| 586 | }; | 597 | }; |
| 587 | vex.b = b_x_op.isBaseExtended(); | 598 | const b_x_op_base_ext_enc = b_x_op.baseExtEnc(); |
| 588 | vex.x = b_x_op.isIndexExtended(); | 599 | vex.b = b_x_op_base_ext_enc & 0b01 != 0; |
| | 600 | assert(b_x_op_base_ext_enc & 0b10 == 0); |
| | 601 | const b_x_op_index_ext_enc = b_x_op.indexExtEnc(); |
| | 602 | vex.x = b_x_op_index_ext_enc & 0b01 != 0; |
| | 603 | assert(b_x_op_index_ext_enc & 0b10 == 0); |
| 589 | }, | 604 | }, |
| 590 | } | 605 | } |
| 591 | | 606 | |
| ... | @@ -622,8 +637,8 @@ pub const Instruction = struct { | ... | @@ -622,8 +637,8 @@ pub const Instruction = struct { |
| 622 | } | 637 | } |
| 623 | | 638 | |
| 624 | fn encodeMemory(encoding: Encoding, mem: Memory, operand: Operand, encoder: anytype) !void { | 639 | fn encodeMemory(encoding: Encoding, mem: Memory, operand: Operand, encoder: anytype) !void { |
| 625 | const operand_enc = switch (operand) { | 640 | const operand_enc: u3 = switch (operand) { |
| 626 | .reg => |reg| reg.lowEnc(), | 641 | .reg => |reg| @truncate(reg.enc()), |
| 627 | .none => encoding.modRmExt(), | 642 | .none => encoding.modRmExt(), |
| 628 | else => unreachable, | 643 | else => unreachable, |
| 629 | }; | 644 | }; |
| ... | @@ -635,7 +650,7 @@ pub const Instruction = struct { | ... | @@ -635,7 +650,7 @@ pub const Instruction = struct { |
| 635 | try encoder.modRm_SIBDisp0(operand_enc); | 650 | try encoder.modRm_SIBDisp0(operand_enc); |
| 636 | if (mem.scaleIndex()) |si| { | 651 | if (mem.scaleIndex()) |si| { |
| 637 | const scale = math.log2_int(u4, si.scale); | 652 | const scale = math.log2_int(u4, si.scale); |
| 638 | try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc()); | 653 | try encoder.sib_scaleIndexDisp32(scale, @truncate(si.index.enc())); |
| 639 | } else { | 654 | } else { |
| 640 | try encoder.sib_disp32(); | 655 | try encoder.sib_disp32(); |
| 641 | } | 656 | } |
| ... | @@ -647,21 +662,21 @@ pub const Instruction = struct { | ... | @@ -647,21 +662,21 @@ pub const Instruction = struct { |
| 647 | try encoder.modRm_SIBDisp0(operand_enc); | 662 | try encoder.modRm_SIBDisp0(operand_enc); |
| 648 | if (mem.scaleIndex()) |si| { | 663 | if (mem.scaleIndex()) |si| { |
| 649 | const scale = math.log2_int(u4, si.scale); | 664 | const scale = math.log2_int(u4, si.scale); |
| 650 | try encoder.sib_scaleIndexDisp32(scale, si.index.lowEnc()); | 665 | try encoder.sib_scaleIndexDisp32(scale, @truncate(si.index.enc())); |
| 651 | } else { | 666 | } else { |
| 652 | try encoder.sib_disp32(); | 667 | try encoder.sib_disp32(); |
| 653 | } | 668 | } |
| 654 | try encoder.disp32(sib.disp); | 669 | try encoder.disp32(sib.disp); |
| 655 | }, | 670 | }, |
| 656 | .general_purpose => { | 671 | .general_purpose => { |
| 657 | const dst = base.lowEnc(); | 672 | const dst: u3 = @truncate(base.enc()); |
| 658 | const src = operand_enc; | 673 | const src = operand_enc; |
| 659 | if (dst == 4 or mem.scaleIndex() != null) { | 674 | if (dst == 4 or mem.scaleIndex() != null) { |
| 660 | if (sib.disp == 0 and dst != 5) { | 675 | if (sib.disp == 0 and dst != 5) { |
| 661 | try encoder.modRm_SIBDisp0(src); | 676 | try encoder.modRm_SIBDisp0(src); |
| 662 | if (mem.scaleIndex()) |si| { | 677 | if (mem.scaleIndex()) |si| { |
| 663 | const scale = math.log2_int(u4, si.scale); | 678 | const scale = math.log2_int(u4, si.scale); |
| 664 | try encoder.sib_scaleIndexBase(scale, si.index.lowEnc(), dst); | 679 | try encoder.sib_scaleIndexBase(scale, @truncate(si.index.enc()), dst); |
| 665 | } else { | 680 | } else { |
| 666 | try encoder.sib_base(dst); | 681 | try encoder.sib_base(dst); |
| 667 | } | 682 | } |
| ... | @@ -669,7 +684,7 @@ pub const Instruction = struct { | ... | @@ -669,7 +684,7 @@ pub const Instruction = struct { |
| 669 | try encoder.modRm_SIBDisp8(src); | 684 | try encoder.modRm_SIBDisp8(src); |
| 670 | if (mem.scaleIndex()) |si| { | 685 | if (mem.scaleIndex()) |si| { |
| 671 | const scale = math.log2_int(u4, si.scale); | 686 | const scale = math.log2_int(u4, si.scale); |
| 672 | try encoder.sib_scaleIndexBaseDisp8(scale, si.index.lowEnc(), dst); | 687 | try encoder.sib_scaleIndexBaseDisp8(scale, @truncate(si.index.enc()), dst); |
| 673 | } else { | 688 | } else { |
| 674 | try encoder.sib_baseDisp8(dst); | 689 | try encoder.sib_baseDisp8(dst); |
| 675 | } | 690 | } |
| ... | @@ -678,7 +693,7 @@ pub const Instruction = struct { | ... | @@ -678,7 +693,7 @@ pub const Instruction = struct { |
| 678 | try encoder.modRm_SIBDisp32(src); | 693 | try encoder.modRm_SIBDisp32(src); |
| 679 | if (mem.scaleIndex()) |si| { | 694 | if (mem.scaleIndex()) |si| { |
| 680 | const scale = math.log2_int(u4, si.scale); | 695 | const scale = math.log2_int(u4, si.scale); |
| 681 | try encoder.sib_scaleIndexBaseDisp32(scale, si.index.lowEnc(), dst); | 696 | try encoder.sib_scaleIndexBaseDisp32(scale, @truncate(si.index.enc()), dst); |
| 682 | } else { | 697 | } else { |
| 683 | try encoder.sib_baseDisp32(dst); | 698 | try encoder.sib_baseDisp32(dst); |
| 684 | } | 699 | } |
| ... | @@ -867,7 +882,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { | ... | @@ -867,7 +882,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { |
| 867 | | 882 | |
| 868 | try self.writer.writeByte( | 883 | try self.writer.writeByte( |
| 869 | @as(u8, @intFromBool(fields.w)) << 7 | | 884 | @as(u8, @intFromBool(fields.w)) << 7 | |
| 870 | @as(u8, ~fields.v.enc()) << 3 | | 885 | @as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 | |
| 871 | @as(u8, @intFromBool(fields.l)) << 2 | | 886 | @as(u8, @intFromBool(fields.l)) << 2 | |
| 872 | @as(u8, @intFromEnum(fields.p)) << 0, | 887 | @as(u8, @intFromEnum(fields.p)) << 0, |
| 873 | ); | 888 | ); |
| ... | @@ -875,7 +890,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { | ... | @@ -875,7 +890,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type { |
| 875 | try self.writer.writeByte(0b1100_0101); | 890 | try self.writer.writeByte(0b1100_0101); |
| 876 | try self.writer.writeByte( | 891 | try self.writer.writeByte( |
| 877 | @as(u8, ~@intFromBool(fields.r)) << 7 | | 892 | @as(u8, ~@intFromBool(fields.r)) << 7 | |
| 878 | @as(u8, ~fields.v.enc()) << 3 | | 893 | @as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 | |
| 879 | @as(u8, @intFromBool(fields.l)) << 2 | | 894 | @as(u8, @intFromBool(fields.l)) << 2 | |
| 880 | @as(u8, @intFromEnum(fields.p)) << 0, | 895 | @as(u8, @intFromEnum(fields.p)) << 0, |
| 881 | ); | 896 | ); |