diff options
author | Kartik Agaram <vc@akkartik.com> | 2020-09-27 22:41:55 -0700 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2020-09-27 22:41:55 -0700 |
commit | c8da2350c22bb70ebcd2690c5ed58e80c19d58c2 (patch) | |
tree | 6e8a6aa37d7b178c4d2b07b1d8631176aab7bc48 | |
parent | eee09a56076f40beabea1f9f677d7d6463265bb0 (diff) | |
download | mu-c8da2350c22bb70ebcd2690c5ed58e80c19d58c2.tar.gz |
6888
Teach `bootstrap translate` about the new /xm32 and /x32 arguments.
-rw-r--r-- | 010vm.cc | 2 | ||||
-rw-r--r-- | 032operands.cc | 120 | ||||
-rw-r--r-- | 033check_operands.cc | 17 |
3 files changed, 124 insertions, 15 deletions
diff --git a/010vm.cc b/010vm.cc index f2ea4c9d..85bb4478 100644 --- a/010vm.cc +++ b/010vm.cc @@ -39,7 +39,7 @@ bzero(Xmm, sizeof(Xmm)); cerr << " registers\n"; :(before "End Help Texts") put_new(Help, "registers", - "SubX supports 16 registers: eight 32-bit integer registers and eight double-precision\n" + "SubX supports 16 registers: eight 32-bit integer registers and eight single-precision\n" "floating-point registers. From 0 to 7, they are:\n" " integer: EAX ECX EDX EBX ESP EBP ESI EDI\n" " floating point: XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7\n" diff --git a/032operands.cc b/032operands.cc index ec14efc4..d8837f92 100644 --- a/032operands.cc +++ b/032operands.cc @@ -18,9 +18,10 @@ put_new(Help, "instructions", "Each argument has a type. An instruction won't have more than one argument of\n" "any type.\n" "Each instruction has some set of allowed argument types. It'll reject others.\n" - "The complete list of argument types: mod, subop, r32 (register), rm32\n" - "(register or memory), scale, index, base, disp8, disp16, disp32, imm8,\n" - "imm32.\n" + "The complete list of argument types: mod, subop, r32 (integer register),\n" + "rm32 (integer register or memory), x32 (floating point register),\n" + "xm32 (floating point register or memory), scale, index, base, disp8, disp16,\n" + "disp32,imm8,imm32.\n" "Each of these has its own help page. Try reading 'bootstrap help mod' next.\n" ); :(before "End Help Contents") @@ -51,10 +52,12 @@ set<string> Instruction_arguments; Instruction_arguments.insert("subop"); Instruction_arguments.insert("mod"); Instruction_arguments.insert("rm32"); +Instruction_arguments.insert("xm32"); Instruction_arguments.insert("base"); Instruction_arguments.insert("index"); Instruction_arguments.insert("scale"); Instruction_arguments.insert("r32"); +Instruction_arguments.insert("x32"); Instruction_arguments.insert("disp8"); Instruction_arguments.insert("disp16"); Instruction_arguments.insert("disp32"); @@ -93,18 +96,37 @@ void init_argument_type_help() { "the two use the same bits.\n" ); put(Help, "r32", - "3-bit argument specifying a register argument used directly, without any further addressing modes.\n" + "3-bit argument specifying an integer register argument used directly,\n" + "without any further addressing modes.\n" + ); + put(Help, "x32", + "3-bit argument specifying a floating-point register argument used directly,\n" + "without any further addressing modes.\n" ); put(Help, "rm32", - "32-bit value in register or memory. The precise details of its construction\n" - "depend on the eponymous 3-bit 'rm32' argument, the 'mod' argument, and also\n" - "potentially the 'SIB' arguments ('scale', 'index' and 'base') and a displacement\n" - "('disp8' or 'disp32').\n" + "32-bit value in an integer register or memory. The precise details of its\n" + "construction depend on the eponymous 3-bit 'rm32' argument, the 'mod' argument,\n" + "and also potentially the 'SIB' arguments ('scale', 'index' and 'base')\n" + "and a displacement ('disp8' or 'disp32').\n" + "\n" + "For complete details, spend some time with two tables in the IA-32 software\n" + "developer's manual that are also included in this repo:\n" + " - modrm.pdf: volume 2, table 2-2, \"32-bit addressing with the ModR/M byte.\".\n" + " - sib.pdf: volume 2, table 2-3, \"32-bit addressing with the SIB byte.\".\n" + ); + put(Help, "xm32", + "32-bit value in a floating-point register or memory. The precise details of its\n" + "construction depend on the eponymous 3-bit 'rm32' argument, the 'mod' argument,\n" + "and also potentially the 'SIB' arguments ('scale', 'index' and 'base')\n" + "and a displacement ('disp8' or 'disp32').\n" "\n" "For complete details, spend some time with two tables in the IA-32 software\n" "developer's manual that are also included in this repo:\n" " - modrm.pdf: volume 2, table 2-2, \"32-bit addressing with the ModR/M byte.\".\n" " - sib.pdf: volume 2, table 2-3, \"32-bit addressing with the SIB byte.\".\n" + "\n" + "One subtlety here: while direct mode uses floating-point registers, other addressing\n" + "modes to construct memory addresses use integer registers." ); put(Help, "base", "Additional 3-bit argument (when 'rm32' is 4, unless 'mod' is 3) specifying the\n" @@ -213,6 +235,14 @@ void add_modrm_byte(const line& in, line& out) { reg_subop = hex_byte(curr.data); emit = true; } + else if (has_argument_metadata(curr, "xm32")) { + rm32 = hex_byte(curr.data); + emit = true; + } + else if (has_argument_metadata(curr, "x32")) { + reg_subop = hex_byte(curr.data); + emit = true; + } else if (has_argument_metadata(curr, "subop")) { reg_subop = hex_byte(curr.data); emit = true; @@ -344,6 +374,76 @@ void test_pack_disp8_negative() { ); } +void test_pack_rm32_direct() { + run( + "== code 0x1\n" + // instruction effective address operand displacement immediate\n" + // op subop mod rm32 base index scale r32\n" + // 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes\n" + " 01 3/mod/direct 3/rm32/ebx 0/r32/eax \n" // add EAX to EBX + ); + CHECK_TRACE_CONTENTS( + "transform: packing instruction '01 3/mod/direct 3/rm32/ebx 0/r32/eax'\n" + "transform: instruction after packing: '01 c3'\n" + ); +} + +void test_pack_rm32_indirect() { + transform( + "== code 0x1\n" + // instruction effective address operand displacement immediate\n" + // op subop mod rm32 base index scale r32\n" + // 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes\n" + " 01 0/mod/indirect 3/rm32/ebx 0/r32/eax \n" // add EAX to *EBX + ); + CHECK_TRACE_CONTENTS( + "transform: packing instruction '01 0/mod/indirect 3/rm32/ebx 0/r32/eax'\n" + "transform: instruction after packing: '01 03'\n" + ); +} + +void test_pack_x32() { + run( + "== code 0x1\n" + // instruction effective address operand displacement immediate\n" + // op subop mod rm32 base index scale r32\n" + // 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes\n" + " f3 0f 2a 3/mod/direct 3/rm32/ebx 1/x32 \n" // convert EBX to XMM1 + ); + CHECK_TRACE_CONTENTS( + "transform: packing instruction 'f3 0f 2a 3/mod/direct 3/rm32/ebx 1/x32'\n" + "transform: instruction after packing: 'f3 0f 2a cb'\n" + ); +} + +void test_pack_xm32_direct() { + transform( + "== code 0x1\n" + // instruction effective address operand displacement immediate\n" + // op subop mod rm32 base index scale r32\n" + // 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes\n" + " f3 0f 5e 3/mod/direct 3/xm32 1/x32 \n" // divide XMM1 by XMM3 + ); + CHECK_TRACE_CONTENTS( + "transform: packing instruction 'f3 0f 5e 3/mod/direct 3/xm32 1/x32'\n" + "transform: instruction after packing: 'f3 0f 5e cb'\n" + ); +} + +void test_pack_xm32_indirect() { + transform( + "== code 0x1\n" + // instruction effective address operand displacement immediate\n" + // op subop mod rm32 base index scale r32\n" + // 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes\n" + " f3 0f 5e 0/mod/indirect 3/rm32/ebx 1/x32 \n" // divide XMM1 by *EBX + ); + CHECK_TRACE_CONTENTS( + "transform: packing instruction 'f3 0f 5e 0/mod/indirect 3/rm32/ebx 1/x32'\n" + "transform: instruction after packing: 'f3 0f 5e 0b'\n" + ); +} + //: helper for scenario void transform(const string& text_bytes) { program p; @@ -359,10 +459,10 @@ void test_pack_modrm_imm32() { // instruction effective address operand displacement immediate\n" // op subop mod rm32 base index scale r32\n" // 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes\n" - " 81 0/add/subop 3/mod/direct 3/ebx/rm32 1/imm32 \n" // add 1 to EBX + " 81 0/add/subop 3/mod/direct 3/rm32/ebx 1/imm32 \n" // add 1 to EBX ); CHECK_TRACE_CONTENTS( - "transform: packing instruction '81 0/add/subop 3/mod/direct 3/ebx/rm32 1/imm32'\n" + "transform: packing instruction '81 0/add/subop 3/mod/direct 3/rm32/ebx 1/imm32'\n" "transform: instruction after packing: '81 c3 01 00 00 00'\n" ); } diff --git a/033check_operands.cc b/033check_operands.cc index e6f71094..bbe2837f 100644 --- a/033check_operands.cc +++ b/033check_operands.cc @@ -331,7 +331,7 @@ uint32_t expected_bit_for_received_argument(const word& w, set<string>& instruct for (int i = 0; i < SIZE(w.metadata); ++i) { string/*copy*/ curr = w.metadata.at(i); string expected_metadata = curr; - if (curr == "mod" || curr == "rm32" || curr == "r32" || curr == "scale" || curr == "index" || curr == "base") + if (curr == "mod" || curr == "rm32" || curr == "r32" || curr == "xm32" || curr == "x32" || curr == "scale" || curr == "index" || curr == "base") expected_metadata = "modrm"; else if (!contains_key(Operand_type, curr)) continue; // ignore unrecognized metadata if (found) { @@ -377,14 +377,16 @@ void test_check_missing_mod_argument() { void check_arguments_modrm(const line& inst, const word& op) { if (all_hex_bytes(inst)) return; // deliberately programming in raw hex; we'll raise a warning elsewhere check_argument_metadata_present(inst, "mod", op); - check_argument_metadata_present(inst, "rm32", op); + if (!has_argument_metadata(inst, "rm32") && !has_argument_metadata(inst, "xm32")) + raise << "'" << to_string(inst) << "'" << maybe_name(op) << ": missing rm32 (or xm32) argument\n" << end(); // no check for r32; some instructions don't use it; just assume it's 0 if missing if (op.data == "81" || op.data == "8f" || op.data == "f7" || op.data == "ff") { // keep sync'd with 'help subop' check_argument_metadata_present(inst, "subop", op); check_argument_metadata_absent(inst, "r32", op, "should be replaced by subop"); + check_argument_metadata_absent(inst, "x32", op, "should be replaced by subop"); } if (trace_contains_errors()) return; - if (metadata(inst, "rm32").data != "4") return; + if (metadata_m32(inst).data != "4") return; // SIB byte checks uint8_t mod = hex_byte(metadata(inst, "mod").data); if (mod != /*direct*/3) { @@ -398,6 +400,13 @@ void check_arguments_modrm(const line& inst, const word& op) { // no check for scale; 0 (2**0 = 1) by default } +word metadata_m32(const line& inst) { + for (int i = 0; i < SIZE(inst.words); ++i) + if (has_argument_metadata(inst.words.at(i), "rm32") || has_argument_metadata(inst.words.at(i), "xm32")) + return inst.words.at(i); + assert(false); +} + // same as compare_bitvector, with one additional exception for modrm-based // instructions: they may use an extra displacement on occasion void compare_bitvector_modrm(const line& inst, uint8_t expected, const string& maybe_op_name) { @@ -505,7 +514,7 @@ void test_check_missing_rm32_argument() { "81 0/add/subop 0/mod 1/imm32\n" ); CHECK_TRACE_CONTENTS( - "error: '81 0/add/subop 0/mod 1/imm32' (combine rm32 with imm32 based on subop): missing rm32 argument\n" + "error: '81 0/add/subop 0/mod 1/imm32' (combine rm32 with imm32 based on subop): missing rm32 (or xm32) argument\n" ); } |