diff options
-rw-r--r-- | subx/011direct_addressing.cc | 64 | ||||
-rw-r--r-- | subx/012direct_addressing.cc | 28 | ||||
-rw-r--r-- | subx/012indirect_addressing.cc (renamed from subx/011indirect_addressing.cc) | 56 |
3 files changed, 74 insertions, 74 deletions
diff --git a/subx/011direct_addressing.cc b/subx/011direct_addressing.cc new file mode 100644 index 00000000..8d280784 --- /dev/null +++ b/subx/011direct_addressing.cc @@ -0,0 +1,64 @@ +//: operating directly on a register + +:(scenario add_r32_to_r32) +% Reg[0].i = 0x10; +% Reg[3].i = 1; +# op ModR/M SIB displacement immediate + 01 d8 # add EBX (reg 3) to EAX (reg 0) ++run: add reg 3 to effective address ++run: effective address is reg 0 ++run: storing 0x00000011 + +:(before "End Single-Byte Opcodes") +case 0x01: { // add r32 to r/m32 + uint8_t modrm = next(); + uint8_t arg2 = (modrm>>3)&0x7; + trace(2, "run") << "add reg " << NUM(arg2) << " to effective address" << end(); + int32_t* arg1 = effective_address(modrm); + BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i); + break; +} + +:(code) +// Implement tables 2-2 and 2-3 in the Intel manual, Volume 2. +// We return a pointer so that instructions can write to multiple bytes in +// 'Mem' at once. +int32_t* effective_address(uint8_t modrm) { + uint8_t mod = (modrm>>6); + // ignore middle 3 'reg opcode' bits + uint8_t rm = modrm & 0x7; + int32_t* result = 0; + switch (mod) { + case 3: + // mod 3 is just register direct addressing + trace(2, "run") << "effective address is reg " << NUM(rm) << end(); + result = &Reg[rm].i; + break; + // End Mod Special-cases + default: + cerr << "unrecognized mod bits: " << NUM(mod) << '\n'; + exit(1); + } + return result; +} + +//:: subtract + +:(scenario subtract_r32_from_r32) +% Reg[0].i = 10; +% Reg[3].i = 1; +# op ModR/M SIB displacement immediate + 29 d8 # subtract EBX (reg 3) from EAX (reg 0) ++run: subtract reg 3 from effective address ++run: effective address is reg 0 ++run: storing 0x00000009 + +:(before "End Single-Byte Opcodes") +case 0x29: { // subtract r32 from r/m32 + uint8_t modrm = next(); + uint8_t arg2 = (modrm>>3)&0x7; + trace(2, "run") << "subtract reg " << NUM(arg2) << " from effective address" << end(); + int32_t* arg1 = effective_address(modrm); + BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i); + break; +} diff --git a/subx/012direct_addressing.cc b/subx/012direct_addressing.cc deleted file mode 100644 index 6352d90c..00000000 --- a/subx/012direct_addressing.cc +++ /dev/null @@ -1,28 +0,0 @@ -//: operating directly on a register - -:(scenario add_r32_to_r32) -% Reg[0].i = 0x10; -% Reg[3].i = 1; -# op ModR/M SIB displacement immediate - 01 d8 # add EBX (reg 3) to EAX (reg 0) -+run: add reg 3 to effective address -+run: effective address is reg 0 -+run: storing 0x00000011 - -:(before "End Mod Special-cases") -case 3: - // mod 3 is just register direct addressing - trace(2, "run") << "effective address is reg " << NUM(rm) << end(); - result = &Reg[rm].i; - break; - -//:: subtract - -:(scenario subtract_r32_from_r32) -% Reg[0].i = 10; -% Reg[3].i = 1; -# op ModR/M SIB displacement immediate - 29 d8 # subtract EBX (reg 3) from EAX (reg 0) -+run: subtract reg 3 from effective address -+run: effective address is reg 0 -+run: storing 0x00000009 diff --git a/subx/011indirect_addressing.cc b/subx/012indirect_addressing.cc index 8800727e..ee56b2e1 100644 --- a/subx/011indirect_addressing.cc +++ b/subx/012indirect_addressing.cc @@ -11,44 +11,18 @@ +run: effective address is mem at address 0x60 (reg 0) +run: storing 0x00000011 -:(before "End Single-Byte Opcodes") -case 0x01: { // add r32 to r/m32 - uint8_t modrm = next(); - uint8_t arg2 = (modrm>>3)&0x7; - trace(2, "run") << "add reg " << NUM(arg2) << " to effective address" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_ARITHMETIC_OP(+, *arg1, Reg[arg2].i); - break; -} - -:(code) -// Implement tables 2-2 and 2-3 in the Intel manual, Volume 2. -// We return a pointer so that instructions can write to multiple bytes in -// 'Mem' at once. -int32_t* effective_address(uint8_t modrm) { - uint8_t mod = (modrm>>6); - // ignore middle 3 'reg opcode' bits - uint8_t rm = modrm & 0x7; - int32_t* result = 0; - switch (mod) { - case 0: - // mod 0 is usually indirect addressing - switch (rm) { - default: - trace(2, "run") << "effective address is mem at address 0x" << std::hex << Reg[rm].u << " (reg " << NUM(rm) << ")" << end(); - assert(Reg[rm].u + sizeof(int32_t) <= Mem.size()); - result = reinterpret_cast<int32_t*>(&Mem.at(Reg[rm].u)); // rely on the host itself being in little-endian order - break; - // End Mod 0 Special-cases - } - break; - // End Mod Special-cases +:(before "End Mod Special-cases") +case 0: + // mod 0 is usually indirect addressing + switch (rm) { default: - cerr << "unrecognized mod bits: " << NUM(mod) << '\n'; - exit(1); + trace(2, "run") << "effective address is mem at address 0x" << std::hex << Reg[rm].u << " (reg " << NUM(rm) << ")" << end(); + assert(Reg[rm].u + sizeof(int32_t) <= Mem.size()); + result = reinterpret_cast<int32_t*>(&Mem.at(Reg[rm].u)); // rely on the host itself being in little-endian order + break; + // End Mod 0 Special-cases } - return result; -} + break; //: @@ -84,16 +58,6 @@ case 0x03: { // add r/m32 to r32 +run: effective address is mem at address 0x60 (reg 0) +run: storing 0x00000009 -:(before "End Single-Byte Opcodes") -case 0x29: { // subtract r32 from r/m32 - uint8_t modrm = next(); - uint8_t arg2 = (modrm>>3)&0x7; - trace(2, "run") << "subtract reg " << NUM(arg2) << " from effective address" << end(); - int32_t* arg1 = effective_address(modrm); - BINARY_ARITHMETIC_OP(-, *arg1, Reg[arg2].i); - break; -} - //: :(scenario sub_mem_at_r32_from_r32) |