diff --git a/InstructionSets/x86/Decoder.cpp b/InstructionSets/x86/Decoder.cpp index 4b6c788d9..95cb5e14a 100644 --- a/InstructionSets/x86/Decoder.cpp +++ b/InstructionSets/x86/Decoder.cpp @@ -58,14 +58,16 @@ std::pair::InstructionT> Decoder::decode(con #define RegAddr(op, dest, op_size, addr_size) \ SetOpSrcDestSize(op, DirectAddress, dest, op_size); \ displacement_size_ = addr_size; \ - phase_ = Phase::DisplacementOrOperand + phase_ = Phase::DisplacementOrOperand; \ + sign_extend_displacement_ = false /// Handles instructions of the form jjkk, Ax where the former is implicitly an address. #define AddrReg(op, source, op_size, addr_size) \ SetOpSrcDestSize(op, source, DirectAddress, op_size); \ displacement_size_ = addr_size; \ destination_ = Source::DirectAddress; \ - phase_ = Phase::DisplacementOrOperand + phase_ = Phase::DisplacementOrOperand; \ + sign_extend_displacement_ = false /// Covers both `mem/reg, reg` and `reg, mem/reg`. #define MemRegReg(op, format, size) \ @@ -1017,11 +1019,20 @@ std::pair::InstructionT> Decoder::decode(con if(bytes_to_consume == outstanding_bytes) { phase_ = Phase::ReadyToPost; - switch(displacement_size_) { - case DataSize::None: displacement_ = 0; break; - case DataSize::Byte: displacement_ = int8_t(inward_data_); break; - case DataSize::Word: displacement_ = int16_t(inward_data_); break; - case DataSize::DWord: displacement_ = int32_t(inward_data_); break; + if(!sign_extend_displacement_) { + switch(displacement_size_) { + case DataSize::None: displacement_ = 0; break; + case DataSize::Byte: displacement_ = uint8_t(inward_data_); break; + case DataSize::Word: displacement_ = uint16_t(inward_data_); break; + case DataSize::DWord: displacement_ = int32_t(inward_data_); break; + } + } else { + switch(displacement_size_) { + case DataSize::None: displacement_ = 0; break; + case DataSize::Byte: displacement_ = int8_t(inward_data_); break; + case DataSize::Word: displacement_ = int16_t(inward_data_); break; + case DataSize::DWord: displacement_ = int32_t(inward_data_); break; + } } inward_data_ >>= bit_size(displacement_size_); diff --git a/InstructionSets/x86/Decoder.hpp b/InstructionSets/x86/Decoder.hpp index eaaad84e5..00d45ac1b 100644 --- a/InstructionSets/x86/Decoder.hpp +++ b/InstructionSets/x86/Decoder.hpp @@ -193,6 +193,8 @@ template class Decoder { DataSize operand_size_ = DataSize::None; // i.e. size of in-stream operand, if any. DataSize operation_size_ = DataSize::None; // i.e. size of data manipulated by the operation. + bool sign_extend_displacement_ = true; // If set then sign extend any displacement up to the address + // size; otherwise it'll be zero-padded. bool sign_extend_operand_ = false; // If set then sign extend the operand up to the operation size; // otherwise it'll be zero-padded. @@ -223,6 +225,7 @@ template class Decoder { next_inward_data_shift_ = 0; inward_data_ = 0; sign_extend_operand_ = false; + sign_extend_displacement_ = true; } }; diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp index 80fe0464d..d7f3f4c4f 100644 --- a/Machines/PCCompatible/PCCompatible.cpp +++ b/Machines/PCCompatible/PCCompatible.cpp @@ -267,7 +267,6 @@ struct Memory { uint16_t write_back_value_; }; -// TODO: the decoder is clearly sign-extending 8-bit port addresses. That's incorrect. Fix. struct IO { template void out([[maybe_unused]] uint16_t port, [[maybe_unused]] IntT value) { if constexpr (std::is_same_v) {