1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-08-16 16:28:59 +00:00
CLK/InstructionSets/M68k/Executor.hpp

167 lines
5.5 KiB
C++
Raw Normal View History

2022-04-29 21:12:06 +00:00
//
// 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 "Status.hpp"
namespace InstructionSet {
namespace M68k {
2022-05-09 13:24:35 +00:00
/// Maps the 68k function codes such that bits 0, 1 and 2 represent
/// FC0, FC1 and FC2 respectively.
enum class FunctionCode {
UserData = 0b001,
UserProgram = 0b010,
SupervisorData = 0b101,
SupervisorProgram = 0b110,
InterruptAcknowledge = 0b111,
};
2022-05-13 14:59:36 +00:00
/// The Executor is templated on a class that implements bus handling as defined below;
/// the bus handler is responsible for all reads and writes, and will also receive resets and
/// interrupt acknowledgements.
///
/// The executor will provide 32-bit addresses and act as if it had a 32-bit data bus, even
/// if interpretting the original 68000 instruction set.
2022-04-29 21:12:06 +00:00
struct BusHandler {
2022-05-13 14:59:36 +00:00
/// Write @c value of type/size @c IntT to @c address with the processor signalling
/// a FunctionCode of @c function. @c IntT will be one of @c uint8_t, @c uint16_t
/// or @c uint32_t.
template <typename IntT> void write(uint32_t address, IntT value, FunctionCode function);
2022-05-13 14:59:36 +00:00
/// Read and return a value of type/size @c IntT from @c address with the processor signalling
/// a FunctionCode of @c function. @c IntT will be one of @c uint8_t, @c uint16_t
/// or @c uint32_t.
template <typename IntT> IntT read(uint32_t address, FunctionCode function);
2022-05-13 14:59:36 +00:00
/// React to the processor programmatically strobing its RESET output.
2022-05-11 11:52:23 +00:00
void reset();
2022-05-13 14:59:36 +00:00
/// Respond to an interrupt acknowledgement at @c interrupt_level from the processor.
/// Should return @c -1 in order to trigger autovectoring, or the appropriate exception vector
/// number otherwise.
///
/// It is undefined behaviour to return a number greater than 255.
int acknowlege_interrupt(int interrupt_level);
2022-04-29 21:12:06 +00:00
};
/// 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 NullFlowController {
2022-04-29 21:12:06 +00:00
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);
/// Call this at any time to interrupt processing with a bus error;
2022-05-11 14:51:48 +00:00
/// the function code and address must be provided. Internally
/// this will raise a C++ exception, and therefore doesn't return.
[[noreturn]] void signal_bus_error(FunctionCode, uint32_t address);
/// Sets the current input interrupt level.
void set_interrupt_level(int);
// Flow control; Cf. Perform.hpp.
template <bool use_current_instruction_pc = true> void raise_exception(int);
2022-05-03 01:27:58 +00:00
void did_update_status();
2022-05-04 12:26:11 +00:00
template <typename IntT> void complete_bcc(bool matched_condition, IntT offset);
void complete_dbcc(bool matched_condition, bool overflowed, int16_t offset);
void bsr(uint32_t offset);
2022-05-09 20:35:17 +00:00
void jmp(uint32_t);
void jsr(uint32_t offset);
2022-05-09 20:35:17 +00:00
void rtr();
void rts();
void rte();
void stop();
2022-05-11 11:52:23 +00:00
void reset();
2022-05-09 20:35:17 +00:00
2022-05-07 12:15:26 +00:00
void link(Preinstruction instruction, uint32_t offset);
2022-05-04 12:26:11 +00:00
void unlink(uint32_t &address);
2022-05-09 20:35:17 +00:00
void pea(uint32_t address);
2022-05-11 11:52:23 +00:00
void move_to_usp(uint32_t address);
void move_from_usp(uint32_t &address);
2022-05-05 16:27:36 +00:00
template <typename IntT> void movep(Preinstruction instruction, uint32_t source, uint32_t dest);
2022-05-06 13:45:06 +00:00
template <typename IntT> void movem_toM(Preinstruction instruction, uint32_t source, uint32_t dest);
template <typename IntT> void movem_toR(Preinstruction instruction, uint32_t source, uint32_t dest);
2022-05-09 20:35:17 +00:00
2022-05-06 16:23:04 +00:00
void tas(Preinstruction instruction, uint32_t address);
2022-05-02 16:57:45 +00:00
// TODO: ownership of this shouldn't be here.
struct Registers {
uint32_t data[8], address[7];
uint32_t user_stack_pointer;
uint32_t supervisor_stack_pointer;
uint16_t status;
uint32_t program_counter;
};
Registers get_state();
void set_state(const Registers &);
2022-04-29 21:12:06 +00:00
private:
void run(int &);
2022-04-29 21:12:06 +00:00
BusHandler &bus_handler_;
Predecoder<model> decoder_;
2022-05-11 11:52:23 +00:00
void reset_processor();
struct EffectiveAddress {
CPU::SlicedInt32 value;
2022-05-01 19:12:13 +00:00
bool requires_fetch;
};
EffectiveAddress calculate_effective_address(Preinstruction instruction, uint16_t opcode, int index);
2022-04-29 21:12:06 +00:00
void read(DataSize size, uint32_t address, CPU::SlicedInt32 &value);
void write(DataSize size, uint32_t address, CPU::SlicedInt32 value);
template <typename IntT> IntT read(uint32_t address, bool is_from_pc = false);
template <typename IntT> void write(uint32_t address, IntT value);
template <typename IntT> IntT read_pc();
uint32_t index_8bitdisplacement();
2022-04-29 21:12:06 +00:00
// Processor state.
Status status_;
CPU::SlicedInt32 program_counter_;
CPU::SlicedInt32 registers_[16]; // D0D8, followed by A0A8.
2022-04-30 12:38:28 +00:00
CPU::SlicedInt32 stack_pointers_[2];
uint32_t instruction_address_;
uint16_t instruction_opcode_;
2022-05-03 01:27:58 +00:00
int active_stack_pointer_ = 0;
// Bus state.
int interrupt_input_ = 0;
// A lookup table to ensure that A7 is adjusted by 2 rather than 1 in
// postincrement and predecrement mode.
static constexpr uint32_t byte_increments[] = {
1, 1, 1, 1, 1, 1, 1, 2
};
2022-04-29 21:12:06 +00:00
};
}
}
#include "Implementation/ExecutorImplementation.hpp"
2022-04-29 21:12:06 +00:00
#endif /* InstructionSets_M68k_Executor_hpp */