diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 49ddb021f..034445efe 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -111,40 +111,133 @@ template void Processor: active_program_->destination->halves.low.halves.low = uint8_t(result); } break; - // ADD and ADDA add two quantities, the latter sign extending and without setting any flags. - case Operation::ADDb: { - const uint8_t source = active_program_->source->halves.low.halves.low; - const uint8_t destination = active_program_->destination->halves.low.halves.low; - const int result = destination + source; + // ADD and ADDA add two quantities, the latter sign extending and without setting any flags; + // ADDQ and SUBQ act as ADD and SUB, but taking the second argument from the instruction code. +#define addop(a, b) a + b +#define subop(a, b) a - b - zero_result_ = active_program_->destination->halves.low.halves.low = uint8_t(result); - extend_flag_ = carry_flag_ = result & ~0xff; - negative_flag_ = result & 0x80; - overflow_flag_ = add_overflow() & 0x80; +#define addsubb(a, b, dest, op, overflow) \ + const auto source = a; \ + const auto destination = b; \ + const int result = op(destination, source); \ +\ + zero_result_ = dest = uint8_t(result); \ + extend_flag_ = carry_flag_ = result & ~0xff; \ + negative_flag_ = result & 0x80; \ + overflow_flag_ = overflow() & 0x80; + +#define addsubw(a, b, dest, op, overflow) \ + const auto source = a; \ + const auto destination = b; \ + const int result = op(destination, source); \ +\ + zero_result_ = dest = uint16_t(result); \ + extend_flag_ = carry_flag_ = result & ~0xffff; \ + negative_flag_ = result & 0x8000; \ + overflow_flag_ = overflow() & 0x8000; + +#define addsubl(a, b, dest, op, overflow) \ + const auto source = a; \ + const auto destination = b; \ + const uint64_t result = op(destination, source); \ +\ + zero_result_ = dest = uint32_t(result); \ + extend_flag_ = carry_flag_ = result >> 32; \ + negative_flag_ = result & 0x80000000; \ + overflow_flag_ = overflow() & 0x80000000; + +#define addb(a, b, dest) addsubb(a, b, dest, addop, add_overflow) +#define subb(a, b, dest) addsubb(a, b, dest, subop, sub_overflow) +#define addw(a, b, dest) addsubw(a, b, dest, addop, add_overflow) +#define subw(a, b, dest) addsubw(a, b, dest, subop, sub_overflow) +#define addl(a, b, dest) addsubl(a, b, dest, addop, add_overflow) +#define subl(a, b, dest) addsubl(a, b, dest, subop, sub_overflow) + +#define q() (((decoded_instruction_ >> 9)&7) ? ((decoded_instruction_ >> 9)&7) : 8) + + case Operation::ADDb: { + addb( active_program_->source->halves.low.halves.low, + active_program_->destination->halves.low.halves.low, + active_program_->destination->halves.low.halves.low); + } break; + + case Operation::ADDQb: { + addb( q(), + active_program_->destination->halves.low.halves.low, + active_program_->destination->halves.low.halves.low); } break; case Operation::ADDw: { - const uint16_t source = active_program_->source->halves.low.full; - const uint16_t destination = active_program_->destination->halves.low.full; - const int result = destination + source; + addw( active_program_->source->halves.low.full, + active_program_->destination->halves.low.full, + active_program_->destination->halves.low.full); + } break; - zero_result_ = active_program_->destination->halves.low.full = uint16_t(result); - extend_flag_ = carry_flag_ = result & ~0xffff; - negative_flag_ = result & 0x8000; - overflow_flag_ = add_overflow() & 0x8000; + case Operation::ADDQw: { + addw( q(), + active_program_->destination->halves.low.full, + active_program_->destination->halves.low.full); } break; case Operation::ADDl: { - const uint32_t source = active_program_->source->full; - const uint32_t destination = active_program_->destination->full; - const uint64_t result = destination + source; - - zero_result_ = active_program_->destination->full = uint32_t(result); - extend_flag_ = carry_flag_ = result >> 32; - negative_flag_ = result & 0x80000000; - overflow_flag_ = add_overflow() & 0x80000000; + addl( active_program_->source->full, + active_program_->destination->full, + active_program_->destination->full); } break; + case Operation::ADDQl: { + addl( q(), + active_program_->destination->full, + active_program_->destination->full); + } break; + + case Operation::SUBb: { + subb( active_program_->source->halves.low.halves.low, + active_program_->destination->halves.low.halves.low, + active_program_->destination->halves.low.halves.low); + } break; + + case Operation::SUBQb: { + subb( q(), + active_program_->destination->halves.low.halves.low, + active_program_->destination->halves.low.halves.low); + } break; + + case Operation::SUBw: { + subw( active_program_->source->halves.low.full, + active_program_->destination->halves.low.full, + active_program_->destination->halves.low.full); + } break; + + case Operation::SUBQw: { + subw( q(), + active_program_->destination->halves.low.full, + active_program_->destination->halves.low.full); + } break; + + case Operation::SUBl: { + subl( active_program_->source->full, + active_program_->destination->full, + active_program_->destination->full); + } break; + + case Operation::SUBQl: { + subl( q(), + active_program_->destination->full, + active_program_->destination->full); + } break; + +#undef addl +#undef addw +#undef addb +#undef subl +#undef subw +#undef subb +#undef addsubl +#undef addsubw +#undef addsubb +#undef q + case Operation::ADDAw: active_program_->destination->full += int16_t(active_program_->source->halves.low.full); break; @@ -153,6 +246,14 @@ template void Processor: active_program_->destination->full += active_program_->source->full; break; + case Operation::SUBAw: + active_program_->destination->full -= int16_t(active_program_->source->halves.low.full); + break; + + case Operation::SUBAl: + active_program_->destination->full -= active_program_->source->full; + break; + // BRA: alters the program counter, exclusively via the prefetch queue. case Operation::BRA: { const int8_t byte_offset = int8_t(prefetch_queue_.halves.high.halves.low); @@ -653,47 +754,6 @@ template void Processor: active_program_->destination->halves.low.halves.low = uint8_t(result); } break; - case Operation::SUBb: { - const uint8_t source = active_program_->source->halves.low.halves.low; - const uint8_t destination = active_program_->destination->halves.low.halves.low; - const int result = destination - source; - - zero_result_ = active_program_->destination->halves.low.halves.low = uint8_t(result); - extend_flag_ = carry_flag_ = result & ~0xff; - negative_flag_ = result & 0x80; - overflow_flag_ = sub_overflow() & 0x80; - } break; - - case Operation::SUBw: { - const uint16_t source = active_program_->source->halves.low.full; - const uint16_t destination = active_program_->destination->halves.low.full; - const int result = destination - source; - - zero_result_ = active_program_->destination->halves.low.full = uint16_t(result); - extend_flag_ = carry_flag_ = result & ~0xffff; - negative_flag_ = result & 0x8000; - overflow_flag_ = sub_overflow() & 0x8000; - } break; - - case Operation::SUBl: { - const uint32_t source = active_program_->source->full; - const uint32_t destination = active_program_->destination->full; - const uint64_t result = destination - source; - - zero_result_ = active_program_->destination->full = uint32_t(result); - extend_flag_ = carry_flag_ = result >> 32; - negative_flag_ = result & 0x80000000; - overflow_flag_ = sub_overflow() & 0x80000000; - } break; - - case Operation::SUBAw: - active_program_->destination->full -= int16_t(active_program_->source->halves.low.full); - break; - - case Operation::SUBAl: - active_program_->destination->full -= active_program_->source->full; - break; - /* Shifts and rotates. */ diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index 5f5157b82..2bdf3b174 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -330,6 +330,7 @@ struct ProcessorStorageConstructor { ADDSUB, // Maps a register and a register and mode to an ADD or SUB. ADDASUBA, // Maps a destination register and a source mode and register to an ADDA or SUBA. + ADDQSUBQ, // Mags a register and a mode to an ADDQ or SUBQ. BRA, // Maps to a BRA. All fields are decoded at runtime. BccBSR, // Maps to a Bcc or BSR. Other than determining the type of operation, fields are decoded at runtime. @@ -451,6 +452,14 @@ struct ProcessorStorageConstructor { {0xf1c0, 0x90c0, Operation::SUBAw, Decoder::ADDASUBA}, // 4-177 (p281) {0xf1c0, 0x91c0, Operation::SUBAl, Decoder::ADDASUBA}, // 4-177 (p281) + {0xf1c0, 0x5000, Operation::ADDQb, Decoder::ADDQSUBQ}, // 4-11 (p115) + {0xf1c0, 0x5040, Operation::ADDQw, Decoder::ADDQSUBQ}, // 4-11 (p115) + {0xf1c0, 0x5080, Operation::ADDQl, Decoder::ADDQSUBQ}, // 4-11 (p115) + + {0xf1c0, 0x5100, Operation::SUBQb, Decoder::ADDQSUBQ}, // 4-181 (p285) + {0xf1c0, 0x5140, Operation::SUBQw, Decoder::ADDQSUBQ}, // 4-181 (p285) + {0xf1c0, 0x5180, Operation::SUBQl, Decoder::ADDQSUBQ}, // 4-181 (p285) + {0xf1c0, 0x0100, Operation::BTSTb, Decoder::BTST}, // 4-62 (p166) {0xffc0, 0x0800, Operation::BTSTb, Decoder::BTSTIMM}, // 4-63 (p167) @@ -847,6 +856,45 @@ struct ProcessorStorageConstructor { } } break; + case Decoder::ADDQSUBQ: { + storage_.instructions[instruction].set_destination(storage_, ea_mode, ea_register); + + const bool is_long_word_access = ((instruction >> 6)&3) == 2; + const bool is_byte_access = ((instruction >> 6)&3) == 0; + const int mode = combined_mode(ea_mode, ea_register); + switch(is_long_word_access ? l(mode) : bw(mode)) { + default: continue; + + case bw(Dn): + op(Action::PerformOperation, seq("np")); + break; + + case l(Dn): + case l(An): + case bw(An): + op(Action::PerformOperation, seq("np nn")); + break; + + case bw(Ind): + case bw(PostInc): + op(Action::None, seq("nrd np", { a(ea_register) }, !is_byte_access)); + op(Action::PerformOperation, seq("nw", { a(ea_register) }, !is_byte_access)); + if(mode == PostInc) { + op(int(is_byte_access ? Action::Increment1 : Action::Increment2) | MicroOp::DestinationMask); + } + break; + + case l(Ind): + case l(PostInc): + op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("nRd+ nrd np", { ea(1), ea(1) })); + op(Action::PerformOperation, seq("nw- nW", { ea(1), ea(1) })); + if(mode == PostInc) { + op(int(Action::Increment4) | MicroOp::DestinationMask); + } + break; + } + } break; + // This decoder actually decodes nothing; it just schedules a PerformOperation followed by an empty step. case Decoder::BccBSR: { const int condition = (instruction >> 8) & 0xf; diff --git a/Processors/68000/Implementation/68000Storage.hpp b/Processors/68000/Implementation/68000Storage.hpp index 1bfb28de4..f790138be 100644 --- a/Processors/68000/Implementation/68000Storage.hpp +++ b/Processors/68000/Implementation/68000Storage.hpp @@ -47,8 +47,11 @@ class ProcessorStorage { ABCD, SBCD, ADDb, ADDw, ADDl, - SUBb, SUBw, SUBl, + ADDQb, ADDQw, ADDQl, ADDAw, ADDAl, + + SUBb, SUBw, SUBl, + SUBQb, SUBQw, SUBQl, SUBAw, SUBAl, MOVEb, MOVEw, MOVEl, MOVEq,