diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index c15a8ea21..bf4df3819 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -58,6 +58,9 @@ template void Processor: active_micro_op_ = active_program_->micro_operations; } +#define sub_overflow() (source ^ destination) & (destination ^ result) +#define add_overflow() ~(source ^ destination) & (destination ^ result) + switch(active_micro_op_->action) { default: std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << std::endl; @@ -86,7 +89,7 @@ template void Processor: zero_result_ |= result & 0xff; extend_flag_ = carry_flag_ = result & ~0xff; negative_flag_ = result & 0x80; - overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80; + overflow_flag_ = add_overflow() & 0x80; // Store the result. active_program_->destination->halves.low.halves.low = uint8_t(result); @@ -101,7 +104,7 @@ template void Processor: zero_result_ = active_program_->destination->halves.low.halves.low = uint8_t(result); extend_flag_ = carry_flag_ = result & ~0xff; negative_flag_ = result & 0x80; - overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80; + overflow_flag_ = add_overflow() & 0x80; } break; case Operation::ADDw: { @@ -112,7 +115,7 @@ template void Processor: zero_result_ = active_program_->destination->halves.low.full = uint16_t(result); extend_flag_ = carry_flag_ = result & ~0xffff; negative_flag_ = result & 0x8000; - overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x8000; + overflow_flag_ = add_overflow() & 0x8000; } break; case Operation::ADDl: { @@ -123,7 +126,7 @@ template void Processor: zero_result_ = active_program_->destination->halves.low.full = uint32_t(result); extend_flag_ = carry_flag_ = result >> 32; negative_flag_ = result & 0x80000000; - overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80000000; + overflow_flag_ = add_overflow() & 0x80000000; } break; case Operation::ADDAw: @@ -210,6 +213,25 @@ template void Processor: } } break; + /* + CLRs: store 0 to the destination, set the zero flag, and clear + negative, overflow and carry. + */ + case Operation::CLRb: + active_program_->destination->halves.low.halves.low = 0; + negative_flag_ = overflow_flag_ = carry_flag_ = zero_result_ = 0; + break; + + case Operation::CLRw: + active_program_->destination->halves.low.full = 0; + negative_flag_ = overflow_flag_ = carry_flag_ = zero_result_ = 0; + break; + + case Operation::CLRl: + active_program_->destination->full = 0; + negative_flag_ = overflow_flag_ = carry_flag_ = zero_result_ = 0; + break; + /* CMP.b, CMP.l and CMP.w: sets the condition flags (other than extend) based on a subtraction of the source from the destination; the result of the subtraction is not stored. @@ -222,7 +244,7 @@ template void Processor: zero_result_ = result & 0xff; carry_flag_ = result & ~0xff; negative_flag_ = result & 0x80; - overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80; + overflow_flag_ = sub_overflow() & 0x80; } break; case Operation::CMPw: { @@ -233,7 +255,7 @@ template void Processor: zero_result_ = result & 0xffff; carry_flag_ = result & ~0xffff; negative_flag_ = result & 0x8000; - overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x8000; + overflow_flag_ = sub_overflow() & 0x8000; } break; case Operation::CMPl: { @@ -244,7 +266,7 @@ template void Processor: zero_result_ = uint32_t(result); carry_flag_ = result >> 32; negative_flag_ = result & 0x80000000; - overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80000000; + overflow_flag_ = sub_overflow() & 0x80000000; } break; // JMP: copies the source to the program counter. @@ -310,12 +332,111 @@ template void Processor: active_program_->source->halves.low.full = get_status(); break; + /* + NEGs: negatives the destination, setting the zero, + negative, overflow and carry flags appropriate, and extend. + */ + case Operation::NEGb: { + const int source = 0; + const int destination = active_program_->destination->halves.low.halves.low; + const int result = source - destination; + active_program_->destination->halves.low.halves.low = result; + + zero_result_ = result & 0xff; + extend_flag_ = carry_flag_ = result & ~0xff; + negative_flag_ = result & 0x80; + overflow_flag_ = sub_overflow() & 0x80; + } break; + + case Operation::NEGw: { + const int source = 0; + const int destination = active_program_->destination->halves.low.full; + const int result = source - destination; + active_program_->destination->halves.low.full = result; + + zero_result_ = result & 0xffff; + extend_flag_ = carry_flag_ = result & ~0xffff; + negative_flag_ = result & 0x8000; + overflow_flag_ = sub_overflow() & 0x8000; + } break; + + case Operation::NEGl: { + const int source = 0; + const int destination = active_program_->destination->full; + int64_t result = source - destination; + active_program_->destination->full = uint32_t(result); + + zero_result_ = uint_fast32_t(result); + extend_flag_ = carry_flag_ = result >> 32; + negative_flag_ = result & 0x80000000; + overflow_flag_ = sub_overflow() & 0x80000000; + } break; + + /* + NEGXs: NEG, with extend. + */ + case Operation::NEGXb: { + const int source = 0; + const int destination = active_program_->destination->halves.low.halves.low; + const int result = source - destination - (extend_flag_ ? 1 : 0); + active_program_->destination->halves.low.halves.low = result; + + zero_result_ = result & 0xff; + extend_flag_ = carry_flag_ = result & ~0xff; + negative_flag_ = result & 0x80; + overflow_flag_ = sub_overflow() & 0x80; + } break; + + case Operation::NEGXw: { + const int source = 0; + const int destination = active_program_->destination->halves.low.full; + const int result = source - destination - (extend_flag_ ? 1 : 0); + active_program_->destination->halves.low.full = result; + + zero_result_ = result & 0xffff; + extend_flag_ = carry_flag_ = result & ~0xffff; + negative_flag_ = result & 0x8000; + overflow_flag_ = sub_overflow() & 0x8000; + } break; + + case Operation::NEGXl: { + const int source = 0; + const int destination = active_program_->destination->full; + int64_t result = source - destination - (extend_flag_ ? 1 : 0); + active_program_->destination->full = result; + + zero_result_ = result; + extend_flag_ = carry_flag_ = result >> 32; + negative_flag_ = result & 0x80000000; + overflow_flag_ = sub_overflow() & 0x80000000; + } break; + /* The no-op. */ case Operation::None: break; + // NOTs: take the logical inverse, affecting the negative and zero flags. + + case Operation::NOTb: + active_program_->destination->halves.low.halves.low ^= 0xff; + zero_result_ = active_program_->destination->halves.low.halves.low; + negative_flag_ = zero_result_ & 0x80; + break; + + case Operation::NOTw: + active_program_->destination->halves.low.full ^= 0xffff; + zero_result_ = active_program_->destination->halves.low.full; + negative_flag_ = zero_result_ & 0x8000; + break; + + case Operation::NOTl: + active_program_->destination->full ^= 0xffffffff; + zero_result_ = active_program_->destination->full; + negative_flag_ = zero_result_ & 0x80000000; + break; + /* SBCD subtracts the lowest byte of the source from that of the destination using BCD arithmetic, obeying the extend flag. diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index 0a6e6e5c2..38e255ed4 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -270,6 +270,7 @@ struct ProcessorStorageConstructor { BTSTIMM, // six lowest bits are [mode, register], decoding to BTST # CMP, DBcc, // the low three bits nominate a register; everything else is decoded in real time + CLRNEGNEGXNOT, }; using Operation = ProcessorStorage::Operation; @@ -343,6 +344,19 @@ struct ProcessorStorageConstructor { {0xffc0, 0x0800, Operation::BTSTb, Decoder::BTSTIMM}, // 4-63 (p167) {0xf0f8, 0x50c8, Operation::DBcc, Decoder::DBcc}, // 4-91 (p195) + + {0xffc0, 0x4200, Operation::CLRb, Decoder::CLRNEGNEGXNOT}, // 4-73 (p177) + {0xffc0, 0x4240, Operation::CLRw, Decoder::CLRNEGNEGXNOT}, // 4-73 (p177) + {0xffc0, 0x4280, Operation::CLRl, Decoder::CLRNEGNEGXNOT}, // 4-73 (p177) + {0xffc0, 0x4400, Operation::NEGb, Decoder::CLRNEGNEGXNOT}, // 4-144 (p248) + {0xffc0, 0x4440, Operation::NEGw, Decoder::CLRNEGNEGXNOT}, // 4-144 (p248) + {0xffc0, 0x4480, Operation::NEGl, Decoder::CLRNEGNEGXNOT}, // 4-144 (p248) + {0xffc0, 0x4000, Operation::NEGXb, Decoder::CLRNEGNEGXNOT}, // 4-146 (p250) + {0xffc0, 0x4040, Operation::NEGXw, Decoder::CLRNEGNEGXNOT}, // 4-146 (p250) + {0xffc0, 0x4080, Operation::NEGXl, Decoder::CLRNEGNEGXNOT}, // 4-146 (p250) + {0xffc0, 0x4600, Operation::NOTb, Decoder::CLRNEGNEGXNOT}, // 4-148 (p250) + {0xffc0, 0x4640, Operation::NOTw, Decoder::CLRNEGNEGXNOT}, // 4-148 (p250) + {0xffc0, 0x4680, Operation::NOTl, Decoder::CLRNEGNEGXNOT}, // 4-148 (p250) }; std::vector micro_op_pointers(65536, std::numeric_limits::max()); @@ -827,6 +841,99 @@ struct ProcessorStorageConstructor { } } break; + case Decoder::CLRNEGNEGXNOT: { + const bool is_byte_access = !!((instruction >> 6)&3); + const bool is_long_word_access = ((instruction >> 6)&3) == 2; + + storage_.instructions[instruction].set_destination(storage_, ea_mode, ea_register); + + const int mode = combined_mode(ea_mode, ea_register); + switch((is_long_word_access ? 0x100 : 0x000) | mode) { + default: continue; + + case 0x000: // [CLR/NEG/NEGX/NOT].bw Dn + case 0x100: // [CLR/NEG/NEGX/NOT].l Dn + op(Action::PerformOperation, seq("np")); + break; + + case 0x002: // [CLR/NEG/NEGX/NOT].bw (An) + case 0x003: // [CLR/NEG/NEGX/NOT].bw (An)+ + op(Action::None, seq("nrd", { a(ea_register) }, !is_byte_access)); + op(Action::PerformOperation, seq("np nw", { a(ea_register) }, !is_byte_access)); + if(ea_mode == 0x03) { + op(int(is_byte_access ? Action::Increment1 : Action::Increment2) | MicroOp::DestinationMask); + } + break; + + case 0x102: // [CLR/NEG/NEGX/NOT].l (An) + case 0x103: // [CLR/NEG/NEGX/NOT].l (An)+ + op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("nRd+ nrd", { ea(1), ea(1) })); + op(Action::PerformOperation, seq("np nw- nW", { ea(1), ea(1) })); + if(ea_mode == 0x03) { + op(int(Action::Increment4) | MicroOp::DestinationMask); + } + break; + + case 0x004: // [CLR/NEG/NEGX/NOT].bw -(An) + op( int(is_byte_access ? Action::Decrement1 : Action::Decrement2) | MicroOp::DestinationMask, + seq("nrd", { a(ea_register) }, !is_byte_access)); + op(Action::PerformOperation, seq("np nw", { a(ea_register) }, !is_byte_access)); + break; + + case 0x104: // [CLR/NEG/NEGX/NOT].l -(An) + op(int(Action::Decrement4) | MicroOp::DestinationMask); + op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, + seq("n nRd+ nrd", { ea(1), ea(1) })); + op(Action::PerformOperation, seq("np nw- nW", { ea(1), ea(1) })); + break; + + case 0x005: // [CLR/NEG/NEGX/NOT].bw (d16, An) + case 0x006: // [CLR/NEG/NEGX/NOT].bw (d8, An, Xn) + op( calc_action_for_mode(ea_mode) | MicroOp::DestinationMask, + seq(pseq("np nrd", ea_mode), { ea(1) }, + !is_byte_access)); + op(Action::PerformOperation, seq("np nw", { ea(1) }, !is_byte_access)); + break; + + case 0x105: // [CLR/NEG/NEGX/NOT].l (d16, An) + case 0x106: // [CLR/NEG/NEGX/NOT].l (d8, An, Xn) + op( calc_action_for_mode(ea_mode) | MicroOp::DestinationMask, + seq(pseq("np nRd+ nrd", ea_mode), { ea(1), ea(1) })); + op(Action::PerformOperation, seq("np nw- nW", { ea(1), ea(1) })); + break; + + case 0x010: // [CLR/NEG/NEGX/NOT].bw (xxx).w + op( int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, + seq("np nrd", { ea(1) }, !is_byte_access)); + op(Action::PerformOperation, + seq("np nw", { ea(1) }, !is_byte_access)); + break; + + case 0x110: // [CLR/NEG/NEGX/NOT].l (xxx).w + op( int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, + seq("np nRd+ nrd", { ea(1), ea(1) })); + op(Action::PerformOperation, + seq("np nw- nW", { ea(1), ea(1) })); + break; + + case 0x011: // [CLR/NEG/NEGX/NOT].bw (xxx).l + op(Action::None, seq("np")); + op( int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, + seq("np nrd", { ea(1) }, !is_byte_access)); + op(Action::PerformOperation, + seq("np nw", { ea(1) }, !is_byte_access)); + break; + + case 0x111: // [CLR/NEG/NEGX/NOT].l (xxx).l + op(Action::None, seq("np")); + op( int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, + seq("np nRd+ nrd", { ea(1), ea(1) })); + op(Action::PerformOperation, + seq("np nw- nW", { ea(1), ea(1) })); + break; + } + } break; + case Decoder::CMP: { const auto source_register = (instruction >> 9) & 7; diff --git a/Processors/68000/Implementation/68000Storage.hpp b/Processors/68000/Implementation/68000Storage.hpp index cc1ed2a4e..e6fed625c 100644 --- a/Processors/68000/Implementation/68000Storage.hpp +++ b/Processors/68000/Implementation/68000Storage.hpp @@ -62,6 +62,11 @@ class ProcessorStorage { JMP, BRA, Bcc, DBcc, + + CLRb, CLRw, CLRl, + NEGXb, NEGXw, NEGXl, + NEGb, NEGw, NEGl, + NOTb, NOTw, NOTl, }; /*!