mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-23 03:32:32 +00:00
Start drafting an Executor.
This commit is contained in:
parent
a103f30d51
commit
9359f6477b
@ -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 <cassert>
|
||||
|
||||
using namespace InstructionSet::M68k;
|
||||
|
41
InstructionSets/M68k/Executor.cpp
Normal file
41
InstructionSets/M68k/Executor.cpp
Normal file
@ -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 <Model model, typename BusHandler>
|
||||
Executor<model, BusHandler>::Executor(BusHandler &handler) : bus_handler_(handler) {
|
||||
reset();
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
void Executor<model, BusHandler>::reset() {
|
||||
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
void Executor<model, BusHandler>::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<uint16_t>(program_counter_.l));
|
||||
const auto instruction_address = program_counter_.l;
|
||||
program_counter_.l += 2;
|
||||
|
||||
// Obtain the appropriate sequence.
|
||||
Sequence<model> sequence(instruction.operation);
|
||||
|
||||
// Perform it.
|
||||
while(!sequence.empty()) {
|
||||
const auto step = sequence.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
54
InstructionSets/M68k/Executor.hpp
Normal file
54
InstructionSets/M68k/Executor.hpp
Normal file
@ -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 <typename IntT> void write(uint32_t address, IntT value);
|
||||
template <typename IntT> 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 <Model model, typename BusHandler> 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<model> decoder_;
|
||||
|
||||
void reset();
|
||||
|
||||
// Processor state.
|
||||
Status status_;
|
||||
CPU::SlicedInt32 program_counter_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* InstructionSets_M68k_Executor_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;
|
||||
|
||||
/*
|
||||
|
@ -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 = "<group>"; };
|
||||
4BB5B997281B1F7B00522DA9 /* Status.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Status.hpp; sourceTree = "<group>"; };
|
||||
4BB5B99A281B244400522DA9 /* PerformImplementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PerformImplementation.hpp; sourceTree = "<group>"; };
|
||||
4BB5B99B281C805300522DA9 /* Executor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Executor.cpp; sourceTree = "<group>"; };
|
||||
4BB5B99C281C805300522DA9 /* Executor.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Executor.hpp; sourceTree = "<group>"; };
|
||||
4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimedEventLoop.cpp; sourceTree = "<group>"; };
|
||||
4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimedEventLoop.hpp; sourceTree = "<group>"; };
|
||||
4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommodoreGCR.cpp; path = Encodings/CommodoreGCR.cpp; sourceTree = "<group>"; };
|
||||
@ -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 */,
|
||||
|
Loading…
Reference in New Issue
Block a user