From 53f75034fcc432a1b3c3d96e02a6f5e53edf327b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 14 Apr 2019 14:09:28 -0400 Subject: [PATCH] Commits at least to decoding MOVEM. --- .../Implementation/68000Implementation.hpp | 15 ++--- .../68000/Implementation/68000Storage.cpp | 55 +++++++++++++++++++ .../68000/Implementation/68000Storage.hpp | 17 +++++- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 61ce90032..327be6618 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -72,6 +72,7 @@ template void Processor: active_micro_op_ = active_program_->micro_operations; } + auto bus_program = active_micro_op_->bus_program; switch(active_micro_op_->action) { default: std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << std::endl; @@ -192,12 +193,12 @@ template void Processor: program_counter_.full += int16_t(prefetch_queue_.halves.low.full); } program_counter_.full -= 2; - active_micro_op_->bus_program = branch_taken_bus_steps_; + bus_program = branch_taken_bus_steps_; } else { if(byte_offset) { - active_micro_op_->bus_program = branch_byte_not_taken_bus_steps_; + bus_program = branch_byte_not_taken_bus_steps_; } else { - active_micro_op_->bus_program = branch_word_not_taken_bus_steps_; + bus_program = branch_word_not_taken_bus_steps_; } } } break; @@ -212,17 +213,17 @@ template void Processor: // This DBcc will be ignored as the counter has underflowed. // Schedule n np np np and continue. Assumed: the first np // is from where the branch would have been if taken? - active_micro_op_->bus_program = dbcc_condition_false_no_branch_steps_; + bus_program = dbcc_condition_false_no_branch_steps_; dbcc_false_address_ = target_program_counter; } else { // Take the branch. Change PC and schedule n np np. - active_micro_op_->bus_program = dbcc_condition_false_branch_steps_; + bus_program = dbcc_condition_false_branch_steps_; program_counter_.full = target_program_counter; } } else { // This DBcc will be ignored as the condition is true; // perform nn np np and continue. - active_micro_op_->bus_program = dbcc_condition_true_steps_; + bus_program = dbcc_condition_true_steps_; } } break; @@ -804,7 +805,7 @@ template void Processor: // If we've got to a micro-op that includes bus steps, break out of this loop. if(!active_micro_op_->is_terminal()) { - active_step_ = active_micro_op_->bus_program; + active_step_ = bus_program; if(!active_step_->is_terminal()) break; } diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index cabb93e3c..3a969b39f 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -323,6 +323,9 @@ struct ProcessorStorageConstructor { ASLRLSLRROLRROXLRr, // Maps a destination register to a AS[L/R], LS[L/R], RO[L/R], ROX[L/R]; shift quantities are // decoded at runtime. ASLRLSLRROLRROXLRm, // Maps a destination mode and register to a memory-based AS[L/R], LS[L/R], RO[L/R], ROX[L/R]. + + MOVEM, // Maps a mode and register as they were a 'destination' and sets up bus steps with a suitable + // hole for the runtime part to install proper MOVEM activity. }; using Operation = ProcessorStorage::Operation; @@ -459,6 +462,11 @@ struct ProcessorStorageConstructor { {0xf1d8, 0xe050, Operation::ROXRw, Decoder::ASLRLSLRROLRROXLRr}, // 4-163 (p267) {0xf1d8, 0xe090, Operation::ROXRl, Decoder::ASLRLSLRROLRROXLRr}, // 4-163 (p267) {0xffc0, 0xe4c0, Operation::ROXRm, Decoder::ASLRLSLRROLRROXLRm}, // 4-163 (p267) + + {0xffc0, 0x48c0, Operation::MOVEMtoMl, Decoder::MOVEM}, // 4-128 (p232) + {0xffc0, 0x4880, Operation::MOVEMtoMw, Decoder::MOVEM}, // 4-128 (p232) + {0xffc0, 0x4cc0, Operation::MOVEMtoRl, Decoder::MOVEM}, // 4-128 (p232) + {0xffc0, 0x4c80, Operation::MOVEMtoRw, Decoder::MOVEM}, // 4-128 (p232) }; #ifndef NDEBUG @@ -1521,6 +1529,53 @@ struct ProcessorStorageConstructor { op(Action::PerformOperation, seq("np")); } break; + case Decoder::MOVEM: { + // For the sake of commonality, both to R and to M will evaluate their addresses + // as if they were destinations. + storage_.instructions[instruction].set_destination(storage_, ea_mode, ea_register); + + // Standard prefix: acquire the register selection flags and fetch the next program + // word to replace them. + op(Action::CopyNextWord, seq("np")); + + // Do whatever is necessary to calculate the proper start address. + const int mode = combined_mode(ea_mode, ea_register); + const bool is_to_m = (operation == Operation::MOVEMtoMl || operation == Operation::MOVEMtoMw); + switch(mode) { + default: continue; + + case Ind: + case PreDec: + case PostInc: { + // Deal with the illegal combinations. + if(mode == PostInc && is_to_m) continue; + if(mode == PreDec && !is_to_m) continue; + } break; + + case d16An: + case d8AnXn: + case d16PC: + case d8PCXn: + // PC-relative addressing is permitted for moving to registers only. + if((mode == d16PC || mode == d8PCXn) && is_to_m) continue; + op(calc_action_for_mode(mode) | MicroOp::DestinationMask, seq(pseq("np", mode))); + break; + + case XXXl: + op(Action::None, seq("np")); + case XXXw: + op(address_assemble_for_mode(mode) | MicroOp::DestinationMask, seq("np")); + break; + } + + // Standard suffix: perform the MOVEM, which will mean evaluating the + // register selection flags and substituting the necessary reads or writes. + op(Action::PerformOperation); + + // A final program fetch will cue up the next instruction. + op(Action::None, seq("np")); + } break; + // Decodes the format used by most MOVEs and all MOVEAs. case Decoder::MOVE: { const int destination_mode = (instruction >> 6) & 7; diff --git a/Processors/68000/Implementation/68000Storage.hpp b/Processors/68000/Implementation/68000Storage.hpp index 92939b739..f7971960e 100644 --- a/Processors/68000/Implementation/68000Storage.hpp +++ b/Processors/68000/Implementation/68000Storage.hpp @@ -77,6 +77,9 @@ class ProcessorStorage { RORb, RORw, RORl, RORm, ROXLb, ROXLw, ROXLl, ROXLm, ROXRb, ROXRw, ROXRl, ROXRm, + + MOVEMtoRl, MOVEMtoRw, + MOVEMtoMl, MOVEMtoMw, }; /*! @@ -205,6 +208,9 @@ class ProcessorStorage { /// Copies the next two prefetch words into one of the bus_data_. AssembleLongWordDataFromPrefetch, + + /// Copies the low part of the prefetch queue into next_word_. + CopyNextWord, }; static const int SourceMask = 1 << 30; static const int DestinationMask = 1 << 29; @@ -282,7 +288,8 @@ class ProcessorStorage { Program *active_program_ = nullptr; MicroOp *active_micro_op_ = nullptr; BusStep *active_step_ = nullptr; - uint16_t decoded_instruction_; + uint16_t decoded_instruction_ = 0; + uint16_t next_word_ = 0; /// Copies address_[7] to the proper stack pointer based on current mode. void write_back_stack_pointer(); @@ -290,6 +297,14 @@ class ProcessorStorage { /// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated. void set_is_supervisor(bool); + // Transient storage for MOVEM. + uint32_t movem_addresses_[16]; + RegisterPair32 movem_spare_value_; + + /*! + Evaluates the conditional described by @c code and returns @c true or @c false to + indicate the result of that evaluation. + */ inline bool evaluate_condition(uint8_t code) { switch(code & 0xf) { default: