diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 6c7d442d2..b3884fa18 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -6,6 +6,28 @@ // Copyright © 2019 Thomas Harte. All rights reserved. // +#define get_status() \ + ( \ + (carry_flag_ ? 0x0001 : 0x0000) | \ + (overflow_flag_ ? 0x0002 : 0x0000) | \ + (zero_result_ ? 0x0000 : 0x0004) | \ + (negative_flag_ ? 0x0008 : 0x0000) | \ + (extend_flag_ ? 0x0010 : 0x0000) | \ + (interrupt_level_ << 8) | \ + (trace_flag_ ? 0x8000 : 0x0000) | \ + (is_supervisor_ << 13) \ + ) + +#define set_status(x) \ + carry_flag_ = (x) & 0x0001; \ + overflow_flag_ = (x) & 0x0002; \ + zero_result_ = ((x) & 0x0004) ^ 0x0004; \ + negative_flag_ = (x) & 0x0008; \ + extend_flag_ = (x) & 0x0010; \ + interrupt_level_ = ((x) >> 8) & 7; \ + trace_flag_ = (x) & 0x8000; \ + is_supervisor_ = ((x) >> 13) & 1; + template void Processor::run_for(HalfCycles duration) { HalfCycles remaining_duration = duration + half_cycles_left_to_run_; while(remaining_duration > HalfCycles(0)) { @@ -55,7 +77,7 @@ template void Processor: if(result > 0x99) result += 0x60; // Set all flags essentially as if this were normal addition. - zero_flag_ |= result & 0xff; + zero_result_ |= result & 0xff; extend_flag_ = carry_flag_ = result & ~0xff; negative_flag_ = result & 0x80; overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80; @@ -76,7 +98,7 @@ template void Processor: if(result > 0x99) result -= 0x60; // Set all flags essentially as if this were normal subtraction. - zero_flag_ |= result & 0xff; + zero_result_ |= result & 0xff; extend_flag_ = carry_flag_ = result & ~0xff; negative_flag_ = result & 0x80; overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80; @@ -90,20 +112,20 @@ template void Processor: and set negative, zero, overflow and carry as appropriate. */ case Operation::MOVEb: - zero_flag_ = active_program_->destination->halves.low.halves.low = active_program_->source->halves.low.halves.low; - negative_flag_ = zero_flag_ & 0x80; + zero_result_ = active_program_->destination->halves.low.halves.low = active_program_->source->halves.low.halves.low; + negative_flag_ = zero_result_ & 0x80; overflow_flag_ = carry_flag_ = 0; break; case Operation::MOVEw: - zero_flag_ = active_program_->destination->halves.low.full = active_program_->source->halves.low.full; - negative_flag_ = zero_flag_ & 0x8000; + zero_result_ = active_program_->destination->halves.low.full = active_program_->source->halves.low.full; + negative_flag_ = zero_result_ & 0x8000; overflow_flag_ = carry_flag_ = 0; break; case Operation::MOVEl: - zero_flag_ = active_program_->destination->full = active_program_->source->full; - negative_flag_ = zero_flag_ & 0x80000000; + zero_result_ = active_program_->destination->full = active_program_->source->full; + negative_flag_ = zero_result_ & 0x80000000; overflow_flag_ = carry_flag_ = 0; break; @@ -122,6 +144,21 @@ template void Processor: active_program_->destination->full = active_program_->source->full; break; + /* + Status word moves. + */ + + case Operation::MOVEtoSR: + set_status(active_program_->source->full); + break; + + case Operation::MOVEfromSR: + active_program_->source->halves.low.full = get_status(); + break; + + /* + Development period debugging. + */ default: std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl; break; @@ -129,20 +166,20 @@ template void Processor: break; case int(MicroOp::Action::SetMoveFlagsb): - zero_flag_ = active_program_->source->halves.low.halves.low; - negative_flag_ = zero_flag_ & 0x80; + zero_result_ = active_program_->source->halves.low.halves.low; + negative_flag_ = zero_result_ & 0x80; overflow_flag_ = carry_flag_ = 0; break; case int(MicroOp::Action::SetMoveFlagsw): - zero_flag_ = active_program_->source->halves.low.full; - negative_flag_ = zero_flag_ & 0x8000; + zero_result_ = active_program_->source->halves.low.full; + negative_flag_ = zero_result_ & 0x8000; overflow_flag_ = carry_flag_ = 0; break; case int(MicroOp::Action::SetMoveFlagsl): - zero_flag_ = active_program_->source->full; - negative_flag_ = zero_flag_ & 0x80000000; + zero_result_ = active_program_->source->full; + negative_flag_ = zero_result_ & 0x80000000; overflow_flag_ = carry_flag_ = 0; break; @@ -322,15 +359,7 @@ template ProcessorState Processor void Processor: stack_pointers_[0].full = state.user_stack_pointer; stack_pointers_[1].full = state.supervisor_stack_pointer; - carry_flag_ = state.status & 0x0001; - overflow_flag_ = state.status & 0x0002; - zero_flag_ = (state.status & 0x0004) ^ 0x0004; - negative_flag_ = state.status & 0x0008; - extend_flag_ = state.status & 0x0010; + set_status(state.status); - is_supervisor_ = (state.status >> 13) & 1; address_[7] = stack_pointers_[is_supervisor_]; - - // TODO: rest of status word: interrupt level, trace flag. } + +#undef get_status +#undef set_status diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index c19db8839..b61809fb1 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -18,6 +18,17 @@ struct ProcessorStorageConstructor { using BusStep = ProcessorStorage::BusStep; + int calc_action_for_mode(int mode) const { + using Action = ProcessorBase::MicroOp::Action; + switch(mode & 0xff) { + default: return 0; + case 0x12: return int(Action::CalcD16PC); // (d16, PC) + case 0x13: return int(Action::CalcD8PCXn); // (d8, PC, Xn) + case 0x05: return int(Action::CalcD16An); // (d16, An) + case 0x06: return int(Action::CalcD8AnXn); // (d8, An, Xn) + } + } + /*! Installs BusSteps that implement the described program into the relevant instance storage, returning the offset within @c all_bus_steps_ at which @@ -163,8 +174,10 @@ struct ProcessorStorageConstructor { } steps.push_back(step); - ++address_iterator; - if(!isupper(access_pattern[1])) ++(*scratch_data); + if(!isupper(access_pattern[1])) { + ++(*scratch_data); + ++address_iterator; + } access_pattern += 2; } break; } @@ -214,7 +227,9 @@ struct ProcessorStorageConstructor { RegOpModeReg, SizeModeRegisterImmediate, DataSizeModeQuick, - RegisterModeModeRegister + RegisterModeModeRegister, // i.e. twelve lowest bits are register, mode, mode, register, for destination and source respectively. + ModeRegister, // i.e. six lowest bits are mode, then register. + MOVEtoSR }; using Operation = ProcessorStorage::Operation; @@ -254,6 +269,8 @@ struct ProcessorStorageConstructor { {0xf000, 0x1000, Operation::MOVEb, Decoder::RegisterModeModeRegister}, // 4-116 (p220) {0xf000, 0x2000, Operation::MOVEl, Decoder::RegisterModeModeRegister}, // 4-116 (p220) {0xf000, 0x3000, Operation::MOVEw, Decoder::RegisterModeModeRegister}, // 4-116 (p220) + + {0xffc0, 0x46c0, Operation::MOVEtoSR, Decoder::MOVEtoSR}, // 6-19 (p473) }; std::vector micro_op_pointers(65536, std::numeric_limits::max()); @@ -295,7 +312,82 @@ struct ProcessorStorageConstructor { } } break; - // Decodes the format used by all the MOVEs. + case Decoder::MOVEtoSR: { + const int source_register = instruction & 7; + const int source_mode = (instruction >> 3) & 7; + + switch(source_mode) { + case 0: // Dn + storage_.instructions[instruction].source = &storage_.data_[source_register]; + break; + + case 1: continue; // An + + default: // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L + storage_.instructions[instruction].source = &storage_.bus_data_[0]; + storage_.instructions[instruction].destination = &storage_.bus_data_[1]; + break; + } + + /* DEVIATION FROM YACHT.TXT: it has all of these reading an extra word from the PC; + this looks like a mistake so I've padded with nil cycles in the middle. */ + switch( (source_mode == 7) ? (0x10 | source_register) : source_mode) { + case 0x00: // MOVE Dn, SR + op(Action::PerformOperation, seq("nn np")); + op(); + break; + + case 0x02: // MOVE (An), SR + case 0x03: // MOVE (An)+, SR + op(Action::None, seq("nr nn nn np", { &storage_.address_[source_register].full })); + if(source_mode == 0x3) { + op(int(Action::Increment2) | MicroOp::SourceMask); + } + op(Action::PerformOperation); + break; + + case 0x04: // MOVE -(An), SR + op(Action::Decrement2, seq("n nr nn nn np", { &storage_.address_[source_register].full })); + op(Action::PerformOperation); + break; + +#define pseq(x) ((source_mode == 0x06) || (source_mode == 0x13) ? "n" x : x) + + case 0x12: // MOVE (d16, PC), SR + case 0x13: // MOVE (d8, PC, Xn), SR + case 0x05: // MOVE (d16, An), SR + case 0x06: // MOVE (d8, An, Xn), SR + op(calc_action_for_mode(source_mode) | MicroOp::SourceMask, seq(pseq("np nr nn nn np"), { &storage_.effective_address_[0] })); + op(Action::PerformOperation); + break; + +#undef pseq + + case 0x10: // MOVE (xxx).W, SR + op( + int(MicroOp::Action::AssembleWordFromPrefetch) | MicroOp::SourceMask, + seq("np nr nn nn np", { &storage_.effective_address_[0] })); + op(Action::PerformOperation); + break; + + case 0x11: // MOVE (xxx).L, SR + op(Action::None, seq("np")); + op(int(MicroOp::Action::AssembleLongWordFromPrefetch) | MicroOp::SourceMask, seq("np nr", { &storage_.effective_address_[0] })); + op(Action::PerformOperation, seq("nn nn np")); + op(); + break; + + case 0x14: // MOVE #, SR + storage_.instructions[instruction].source = &storage_.prefetch_queue_; + op(int(Action::PerformOperation), seq("np nn nn np")); + op(); + break; + + default: continue; + } + } break; + + // Decodes the format used by most MOVEs and all MOVEAs. case Decoder::RegisterModeModeRegister: { const int source_register = instruction & 7; const int source_mode = (instruction >> 3) & 7; @@ -445,18 +537,44 @@ struct ProcessorStorageConstructor { operation = Operation::MOVEAl; case 0x10200: // MOVE.l (An), Dn case 0x10300: // MOVE.l (An)+, Dn - op(Action::CopySourceToEffectiveAddress, seq("nR nr np", {&storage_.effective_address_[0], &storage_.effective_address_[0]})); + op(Action::CopySourceToEffectiveAddress, seq("nR nr np", { &storage_.effective_address_[0] })); if(source_mode == 0x3) { op(int(Action::Increment4) | MicroOp::SourceMask); } op(Action::PerformOperation); break; - case 0x0202: // MOVE (An), (An) - case 0x0302: // MOVE (An)+, (An) - case 0x0203: // MOVE (An), (An)+ - case 0x0303: // MOVE (An)+, (An)+ - // nr nw np + case 0x00202: // MOVE.bw (An), (An) + case 0x00302: // MOVE.bw (An)+, (An) + case 0x00203: // MOVE.bw (An), (An)+ + case 0x00303: // MOVE.bw (An)+, (An)+ + op(Action::None, seq("nr", { &storage_.address_[source_register].full })); + op(Action::PerformOperation, seq("nw np", { &storage_.address_[destination_register].full })); + if(source_mode == 0x3 || destination_mode == 0x3) { + op( + int(is_byte_access ? Action::Increment1 : Action::Increment2) | + (source_mode == 0x3 ? MicroOp::SourceMask : 0) | + (source_mode == 0x3 ? MicroOp::DestinationMask : 0)); + } else { + op(); + } + continue; + + case 0x10202: // MOVE.l (An), (An) + case 0x10302: // MOVE.l (An)+, (An) + case 0x10203: // MOVE.l (An), (An)+ + case 0x10303: // MOVE.l (An)+, (An)+ + op(Action::CopyDestinationToEffectiveAddress); + op(Action::CopySourceToEffectiveAddress, seq("nR nr", { &storage_.effective_address_[0] })); + op(Action::PerformOperation, seq("nW nw np", { &storage_.effective_address_[1] })); + if(source_mode == 0x3 || destination_mode == 0x3) { + op( + int(Action::Increment4) | + (source_mode == 0x3 ? MicroOp::SourceMask : 0) | + (source_mode == 0x3 ? MicroOp::DestinationMask : 0)); + } else { + op(); + } continue; case 0x0204: // MOVE (An), -(An) @@ -620,11 +738,12 @@ struct ProcessorStorageConstructor { // Source = (xxx).L // - case 0x1101: // MOVEA (xxx).W, Dn + case 0x1101: // MOVEA (xxx).L, Dn operation = Operation::MOVEAw; - case 0x1100: // MOVE (xxx).W, Dn - op(int(MicroOp::Action::AssembleWordFromPrefetch) | MicroOp::SourceMask, seq("np np")); - op(Action::PerformOperation, seq("nr np", { &storage_.effective_address_[0] }, !is_byte_access)); + case 0x1100: // MOVE (xxx).L, Dn + op(Action::None, seq("np")); + op(int(MicroOp::Action::AssembleLongWordFromPrefetch) | MicroOp::SourceMask, seq("np nr", { &storage_.effective_address_[0] }, !is_byte_access)); + op(Action::PerformOperation, seq("np")); op(); break; diff --git a/Processors/68000/Implementation/68000Storage.hpp b/Processors/68000/Implementation/68000Storage.hpp index bf057e54c..83a93d58f 100644 --- a/Processors/68000/Implementation/68000Storage.hpp +++ b/Processors/68000/Implementation/68000Storage.hpp @@ -26,11 +26,13 @@ class ProcessorStorage { // Various status bits. int is_supervisor_; - uint_fast32_t zero_flag_; // The zero flag is set if this value is zero. + int interrupt_level_; + uint_fast32_t zero_result_; // The zero flag is set if this value is zero. uint_fast32_t carry_flag_; // The carry flag is set if this value is non-zero. uint_fast32_t extend_flag_; // The extend flag is set if this value is non-zero. uint_fast32_t overflow_flag_; // The overflow flag is set if this value is non-zero. uint_fast32_t negative_flag_; // The negative flag is set if this value is non-zero. + uint_fast32_t trace_flag_; // The trace flag is set if this value is non-zero. // Generic sources and targets for memory operations; // by convention: [0] = source, [1] = destination. @@ -44,7 +46,9 @@ class ProcessorStorage { ADD, AND, EOR, OR, SUB, MOVEb, MOVEw, MOVEl, - MOVEAw, MOVEAl + MOVEAw, MOVEAl, + + MOVEtoSR, MOVEfromSR }; /*! @@ -192,6 +196,7 @@ class ProcessorStorage { RegisterPair32 *source = nullptr; RegisterPair32 *destination = nullptr; Operation operation; + bool requires_supervisor = false; }; // Storage for all the sequences of bus steps and micro-ops used throughout