diff --git a/InstructionSets/M68k/Decoder.cpp b/InstructionSets/M68k/Decoder.cpp index a52c501d8..414b9768d 100644 --- a/InstructionSets/M68k/Decoder.cpp +++ b/InstructionSets/M68k/Decoder.cpp @@ -8,10 +8,6 @@ #include "Decoder.hpp" -// TODO: remove this include. It's a temporary hack to get the performer into the automated build -// while I work on this branch. -#include "Perform.hpp" - #include using namespace InstructionSet::M68k; diff --git a/InstructionSets/M68k/Executor.cpp b/InstructionSets/M68k/Executor.cpp new file mode 100644 index 000000000..2da4177a0 --- /dev/null +++ b/InstructionSets/M68k/Executor.cpp @@ -0,0 +1,41 @@ +// +// Executor.cpp +// Clock Signal +// +// Created by Thomas Harte on 29/04/2022. +// Copyright © 2022 Thomas Harte. All rights reserved. +// + +#include "Executor.hpp" + +using namespace InstructionSet::M68k; + +template +Executor::Executor(BusHandler &handler) : bus_handler_(handler) { + reset(); +} + +template +void Executor::reset() { + +} + +template +void Executor::run_for_instructions(int count) { + while(count--) { + // TODO: check interrupt level, trace flag. + + // Read the next instruction. + const Preinstruction instruction = decoder_.decode(bus_handler_.template read(program_counter_.l)); + const auto instruction_address = program_counter_.l; + program_counter_.l += 2; + + // Obtain the appropriate sequence. + Sequence sequence(instruction.operation); + + // Perform it. + while(!sequence.empty()) { + const auto step = sequence.pop_front(); + } + } +} diff --git a/InstructionSets/M68k/Executor.hpp b/InstructionSets/M68k/Executor.hpp new file mode 100644 index 000000000..a51af6fce --- /dev/null +++ b/InstructionSets/M68k/Executor.hpp @@ -0,0 +1,54 @@ +// +// Executor.hpp +// Clock Signal +// +// Created by Thomas Harte on 29/04/2022. +// Copyright © 2022 Thomas Harte. All rights reserved. +// + +#ifndef InstructionSets_M68k_Executor_hpp +#define InstructionSets_M68k_Executor_hpp + +#include "Decoder.hpp" +#include "Instruction.hpp" +#include "Model.hpp" +#include "Perform.hpp" +#include "Sequence.hpp" +#include "Status.hpp" + +namespace InstructionSet { +namespace M68k { + +struct BusHandler { + template void write(uint32_t address, IntT value); + template IntT read(uint32_t address); +}; + +/// Ties together the decoder, sequencer and performer to provide an executor for 680x0 instruction streams. +/// As is standard for these executors, no bus- or cache-level fidelity to any real 680x0 is attempted. This is +/// simply an executor of 680x0 code. +template class Executor { + public: + Executor(BusHandler &); + + /// Executes the number of instructions specified; + /// other events — such as initial reset or branching + /// to exceptions — may be zero costed, and interrupts + /// will not necessarily take effect immediately when signalled. + void run_for_instructions(int); + + private: + BusHandler &bus_handler_; + Predecoder decoder_; + + void reset(); + + // Processor state. + Status status_; + CPU::SlicedInt32 program_counter_; +}; + +} +} + +#endif /* InstructionSets_M68k_Executor_hpp */ diff --git a/InstructionSets/M68k/Implementation/PerformImplementation.hpp b/InstructionSets/M68k/Implementation/PerformImplementation.hpp index f24a2c938..2dad77da5 100644 --- a/InstructionSets/M68k/Implementation/PerformImplementation.hpp +++ b/InstructionSets/M68k/Implementation/PerformImplementation.hpp @@ -243,21 +243,6 @@ template < dest.l -= src.l; 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); -// -// // A non-zero offset byte branches by just that amount; otherwise use the word -// // after as an offset. In both cases, treat as signed. -// if(byte_offset) { -// program_counter_.l += uint32_t(byte_offset); -// } else { -// program_counter_.l += u_extend16(prefetch_queue_.w); -// } -// program_counter_.l -= 2; -// } break; - // Two BTSTs: set the zero flag according to the value of the destination masked by // the bit named in the source modulo the operation size. // case Operation::BTSTb: @@ -309,63 +294,42 @@ template < // // Special case: the condition code is 1, which is ordinarily false. In that case this // is the trailing step of a BSR. -// case Operation::Bcc: { -// // Grab the 8-bit offset. -// const int8_t byte_offset = int8_t(prefetch_queue_.halves.high.halves.low); -// -// // Check whether this is secretly BSR. -// const bool is_bsr = ((decoded_instruction_.l >> 8) & 0xf) == 1; -// -// // Test the conditional, treating 'false' as true. -// const bool should_branch = is_bsr || evaluate_condition(decoded_instruction_.l >> 8); -// -// // Schedule something appropriate, by rewriting the program for this instruction temporarily. -// if(should_branch) { -// if(byte_offset) { -// program_counter_.l += decltype(program_counter_.l)(byte_offset); -// } else { -// program_counter_.l += u_extend16(prefetch_queue_.w); -// } -// program_counter_.l -= 2; -// bus_program = is_bsr ? bsr_bus_steps_ : branch_taken_bus_steps_; -// } else { -// if(byte_offset) { -// bus_program = branch_byte_not_taken_bus_steps_; -// } else { -// bus_program = branch_word_not_taken_bus_steps_; -// } -// } -// } break; -// -// case Operation::DBcc: { -// // Decide what sort of DBcc this is. -// if(!evaluate_condition(decoded_instruction_.l >> 8)) { -// -- src.w; -// const auto target_program_counter = program_counter_.l + u_extend16(prefetch_queue_.w) - 2; -// -// if(src.w == 0xffff) { -// // 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? -// 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. -// bus_program = dbcc_condition_false_branch_steps_; -// program_counter_.l = target_program_counter; -// } -// } else { -// // This DBcc will be ignored as the condition is true; -// // perform nn np np and continue. -// bus_program = dbcc_condition_true_steps_; -// } -// } break; + case Operation::Bccb: + case Operation::Bccw: + case Operation::Bccl: { + // Test the conditional, treating 'false' as true. + const bool should_branch = status.evaluate_condition(flow_controller.decode_conditional()); - case Operation::Scc: { - dest.b = - status.evaluate_condition(src.l) ? 0xff : 0x00; + // Schedule something appropriate, by rewriting the program for this instruction temporarily. + if(should_branch) { + flow_controller.add_pc(src.l); + } else { + flow_controller.decline_branch(); + } } break; + case Operation::DBcc: + // Decide what sort of DBcc this is. + if(!status.evaluate_condition(flow_controller.decode_conditional())) { + -- src.w; + + if(src.w == 0xffff) { + // This DBcc will be ignored as the counter has underflowed. + flow_controller.decline_branch(); + } else { + // Take the branch. + flow_controller.add_pc(dest.l); + } + } else { + // This DBcc will be ignored as the condition is true. + flow_controller.decline_branch(); + } + break; + + case Operation::Scc: + dest.b = status.evaluate_condition(src.l) ? 0xff : 0x00; + break; + /* CLRs: store 0 to the destination, set the zero flag, and clear negative, overflow and carry. @@ -434,13 +398,9 @@ template < } break; // JMP: copies EA(0) to the program counter. -// case Operation::JMP: -// flow_controller.set_pc(effective_address_[0]); -// break; - -// case Operation::RTS: -// program_counter_ = source_bus_data_; -// break; + case Operation::JMP: + flow_controller.set_pc(flow_controller.effective_address(0)); + break; /* MOVE.b, MOVE.l and MOVE.w: move the least significant byte or word, or the entire long word, @@ -477,6 +437,10 @@ template < dest.l = src.l; break; + case Operation::LEA: + dest.l = flow_controller.effective_address(0); + break; + // case Operation::PEA: // destination_bus_data_ = effective_address_[0]; // break; @@ -823,8 +787,7 @@ template < /* The no-op. */ - case Operation::NOP: - break; + case Operation::NOP: break; /* LINK and UNLINK help with stack frames, allowing a certain @@ -1248,6 +1211,12 @@ template < // uint8_t(current_status >> 8); // } // apply_status(source_bus_data_.l); +// break; + +// case Operation::RTE: +// break; +// +// case Operation::RTR: // break; /* diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 771e04656..af932c3f9 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -894,6 +894,8 @@ 4BB4BFB022A42F290069048D /* MacintoshIMG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB4BFAE22A42F290069048D /* MacintoshIMG.cpp */; }; 4BB4BFB922A4372F0069048D /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB4BFB822A4372E0069048D /* StaticAnalyser.cpp */; }; 4BB4BFBA22A4372F0069048D /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB4BFB822A4372E0069048D /* StaticAnalyser.cpp */; }; + 4BB5B99D281C814E00522DA9 /* Executor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB5B99B281C805300522DA9 /* Executor.cpp */; }; + 4BB5B99E281C814F00522DA9 /* Executor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB5B99B281C805300522DA9 /* Executor.cpp */; }; 4BB697CB1D4B6D3E00248BDF /* TimedEventLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */; }; 4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; }; 4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EA11B587A5100552FC2 /* AppDelegate.swift */; }; @@ -1939,6 +1941,8 @@ 4BB5B996281B1E3F00522DA9 /* Perform.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Perform.hpp; sourceTree = ""; }; 4BB5B997281B1F7B00522DA9 /* Status.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Status.hpp; sourceTree = ""; }; 4BB5B99A281B244400522DA9 /* PerformImplementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PerformImplementation.hpp; sourceTree = ""; }; + 4BB5B99B281C805300522DA9 /* Executor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Executor.cpp; sourceTree = ""; }; + 4BB5B99C281C805300522DA9 /* Executor.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Executor.hpp; sourceTree = ""; }; 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimedEventLoop.cpp; sourceTree = ""; }; 4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimedEventLoop.hpp; sourceTree = ""; }; 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommodoreGCR.cpp; path = Encodings/CommodoreGCR.cpp; sourceTree = ""; }; @@ -3165,8 +3169,10 @@ isa = PBXGroup; children = ( 4B79629F2819681F008130F9 /* Decoder.cpp */, + 4BB5B99B281C805300522DA9 /* Executor.cpp */, 4B7962A4281C2EE3008130F9 /* Sequence.cpp */, 4B79629E2819681F008130F9 /* Decoder.hpp */, + 4BB5B99C281C805300522DA9 /* Executor.hpp */, 4B79629C2819681F008130F9 /* Instruction.hpp */, 4B79629D2819681F008130F9 /* Model.hpp */, 4BB5B996281B1E3F00522DA9 /* Perform.hpp */, @@ -5458,6 +5464,7 @@ 4B1B88C1202E3DB200B67DFF /* MultiConfigurable.cpp in Sources */, 4B055AA31FAE85DF0060FFFF /* ImplicitSectors.cpp in Sources */, 4B8318B322D3E540006DB630 /* Audio.cpp in Sources */, + 4BB5B99E281C814F00522DA9 /* Executor.cpp in Sources */, 4B055AAE1FAE85FD0060FFFF /* TrackSerialiser.cpp in Sources */, 4B89452B201967B4007DE474 /* File.cpp in Sources */, 4B6AAEAC230E40250078E864 /* SCSI.cpp in Sources */, @@ -5708,6 +5715,7 @@ 4BC890D3230F86020025A55A /* DirectAccessDevice.cpp in Sources */, 4B7BA03723CEB86000B98D9E /* BD500.cpp in Sources */, 4B38F3481F2EC11D00D9235D /* AmstradCPC.cpp in Sources */, + 4BB5B99D281C814E00522DA9 /* Executor.cpp in Sources */, 4B8FE2221DA19FB20090D3CE /* MachineController.swift in Sources */, 4B4518A41F75FD1C00926311 /* OricMFMDSK.cpp in Sources */, 4B4B1A3C200198CA00A0F866 /* KonamiSCC.cpp in Sources */,