mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Take a swing at access faults and address errors.
This commit is contained in:
parent
477979c275
commit
ab8e1fdcbf
50
InstructionSets/M68k/ExceptionVectors.hpp
Normal file
50
InstructionSets/M68k/ExceptionVectors.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
//
|
||||
// ExceptionVectors.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 10/05/2022.
|
||||
// Copyright © 2022 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef InstructionSets_M68k_ExceptionVectors_hpp
|
||||
#define InstructionSets_M68k_ExceptionVectors_hpp
|
||||
|
||||
namespace InstructionSet {
|
||||
namespace M68k {
|
||||
|
||||
enum Exception {
|
||||
InitialStackPointer = 0,
|
||||
InitialProgramCounter = 1,
|
||||
AccessFault = 2,
|
||||
AddressError = 3,
|
||||
IllegalInstruction = 4,
|
||||
IntegerDivideByZero = 5,
|
||||
CHK = 6,
|
||||
TRAPV = 7,
|
||||
PrivilegeViolation = 8,
|
||||
Trace = 9,
|
||||
Line1010 = 10,
|
||||
Line1111 = 11,
|
||||
CoprocessorProtocolViolation = 13,
|
||||
FormatError = 14,
|
||||
UninitialisedInterrupt = 15,
|
||||
SpuriousInterrupt = 24,
|
||||
InterruptAutovectorBase = 25,
|
||||
TrapBase = 32,
|
||||
FPBranchOrSetOnUnorderedCondition = 48,
|
||||
FPInexactResult = 49,
|
||||
FPDivideByZero = 50,
|
||||
FPUnderflow = 51,
|
||||
FPOperandError = 52,
|
||||
FPOverflow = 53,
|
||||
FPSignallingNAN = 54,
|
||||
FPUnimplementedDataType = 55,
|
||||
MMUConfigurationError = 56,
|
||||
MMUIllegalOperationError = 57,
|
||||
MMUAccessLevelViolationError = 58,
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* InstructionSets_M68k_ExceptionVectors_hpp */
|
@ -46,6 +46,10 @@ template <Model model, typename BusHandler> class Executor: public NullFlowContr
|
||||
/// 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;
|
||||
/// the function code and address must be provided.
|
||||
void signal_bus_error(FunctionCode, uint32_t address);
|
||||
|
||||
// Flow control; Cf. Perform.hpp.
|
||||
template <bool use_current_instruction_pc = true> void raise_exception(int);
|
||||
|
||||
@ -83,6 +87,8 @@ template <Model model, typename BusHandler> class Executor: public NullFlowContr
|
||||
void set_state(const Registers &);
|
||||
|
||||
private:
|
||||
void run(int &);
|
||||
|
||||
BusHandler &bus_handler_;
|
||||
Predecoder<model> decoder_;
|
||||
|
||||
@ -108,6 +114,7 @@ template <Model model, typename BusHandler> class Executor: public NullFlowContr
|
||||
CPU::SlicedInt32 registers_[16]; // D0–D8, followed by A0–A8.
|
||||
CPU::SlicedInt32 stack_pointers_[2];
|
||||
uint32_t instruction_address_;
|
||||
uint16_t instruction_opcode_;
|
||||
int active_stack_pointer_ = 0;
|
||||
|
||||
// A lookup table to ensure that A7 is adjusted by 2 rather than 1 in
|
||||
|
@ -10,6 +10,8 @@
|
||||
#define InstructionSets_M68k_ExecutorImplementation_hpp
|
||||
|
||||
#include "../Perform.hpp"
|
||||
#include "../ExceptionVectors.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace InstructionSet {
|
||||
@ -19,6 +21,9 @@ namespace M68k {
|
||||
#define Dn(x) registers_[x]
|
||||
#define sp An(7)
|
||||
|
||||
#define AccessException(code, address, vector) \
|
||||
uint64_t(((vector) << 8) | uint64_t(code) | ((address) << 16))
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
Executor<model, BusHandler>::Executor(BusHandler &handler) : bus_handler_(handler) {
|
||||
reset();
|
||||
@ -31,23 +36,31 @@ void Executor<model, BusHandler>::reset() {
|
||||
did_update_status();
|
||||
|
||||
// Seed stack pointer and program counter.
|
||||
sp.l = read<uint32_t>(0);
|
||||
sp.l = read<uint32_t>(0) & 0xffff'fffe;
|
||||
program_counter_.l = read<uint32_t>(4);
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
template <typename IntT>
|
||||
IntT Executor<model, BusHandler>::read(uint32_t address, bool is_from_pc) {
|
||||
// TODO: check for an alignment exception, both here and in write.
|
||||
//
|
||||
const auto code = FunctionCode((status_.is_supervisor_ << 2) | 1 << int(is_from_pc));
|
||||
if(model == Model::M68000 && sizeof(IntT) > 1 && address & 1) {
|
||||
throw AccessException(code, address, Exception::AddressError | (int(is_from_pc) << 3) | (1 << 4));
|
||||
}
|
||||
|
||||
// TODO: omit generation of the FunctionCode if the BusHandler doesn't receive it.
|
||||
return bus_handler_.template read<IntT>(address, FunctionCode((status_.is_supervisor_ << 2) | 1 << int(is_from_pc)));
|
||||
return bus_handler_.template read<IntT>(address, code);
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
template <typename IntT>
|
||||
void Executor<model, BusHandler>::write(uint32_t address, IntT value) {
|
||||
bus_handler_.template write<IntT>(address, value, FunctionCode((status_.is_supervisor_ << 2) | 1));
|
||||
const auto code = FunctionCode((status_.is_supervisor_ << 2) | 1);
|
||||
if(model == Model::M68000 && sizeof(IntT) > 1 && address & 1) {
|
||||
throw AccessException(code, address, Exception::AddressError);
|
||||
}
|
||||
|
||||
bus_handler_.template write<IntT>(address, value, code);
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
@ -209,31 +222,69 @@ typename Executor<model, BusHandler>::EffectiveAddress Executor<model, BusHandle
|
||||
return ea;
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
void Executor<model, BusHandler>::signal_bus_error(FunctionCode code, uint32_t address) {
|
||||
throw AccessException(code, address, Exception::AccessFault);
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
void Executor<model, BusHandler>::run_for_instructions(int count) {
|
||||
while(count) {
|
||||
try {
|
||||
run(count);
|
||||
} catch (uint64_t exception) {
|
||||
// Unpack the exception; this is the converse of the AccessException macro.
|
||||
const int vector_address = (exception >> 6) & 0xfc;
|
||||
const uint16_t code = uint16_t(exception & 0xff);
|
||||
const uint32_t faulting_address = uint32_t(exception >> 16);
|
||||
|
||||
// Grab the status to store, then switch into supervisor mode.
|
||||
const uint16_t status = status_.status();
|
||||
status_.is_supervisor_ = 1;
|
||||
did_update_status();
|
||||
|
||||
// Push status and the program counter at instruction start.
|
||||
write<uint16_t>(sp.l - 14, code);
|
||||
write<uint32_t>(sp.l - 12, faulting_address);
|
||||
write<uint16_t>(sp.l - 8, instruction_opcode_);
|
||||
write<uint16_t>(sp.l - 6, status);
|
||||
write<uint16_t>(sp.l - 4, instruction_address_);
|
||||
sp.l -= 14;
|
||||
|
||||
// Fetch the new program counter; reset on a double fault.
|
||||
try {
|
||||
program_counter_.l = read<uint32_t>(vector_address);
|
||||
} catch (uint64_t) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
void Executor<model, BusHandler>::run(int &count) {
|
||||
while(count--) {
|
||||
// TODO: check interrupt level, trace flag.
|
||||
|
||||
// Read the next instruction.
|
||||
instruction_address_ = program_counter_.l;
|
||||
const auto opcode = read_pc<uint16_t>();
|
||||
const Preinstruction instruction = decoder_.decode(opcode);
|
||||
instruction_opcode_ = read_pc<uint16_t>();
|
||||
const Preinstruction instruction = decoder_.decode(instruction_opcode_);
|
||||
|
||||
if(!status_.is_supervisor_ && instruction.requires_supervisor()) {
|
||||
raise_exception(8);
|
||||
raise_exception(Exception::PrivilegeViolation);
|
||||
continue;
|
||||
}
|
||||
if(instruction.operation == Operation::Undefined) {
|
||||
switch(opcode & 0xf000) {
|
||||
switch(instruction_opcode_ & 0xf000) {
|
||||
default:
|
||||
raise_exception(4);
|
||||
raise_exception(Exception::IllegalInstruction);
|
||||
continue;
|
||||
case 0xa000:
|
||||
raise_exception(10);
|
||||
raise_exception(Exception::Line1010);
|
||||
continue;
|
||||
case 0xf000:
|
||||
raise_exception(11);
|
||||
raise_exception(Exception::Line1111);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -249,8 +300,8 @@ void Executor<model, BusHandler>::run_for_instructions(int count) {
|
||||
//
|
||||
// TODO: much of this work should be performed by a full Decoder,
|
||||
// so that it can be cached.
|
||||
effective_address_[0] = calculate_effective_address(instruction, opcode, 0);
|
||||
effective_address_[1] = calculate_effective_address(instruction, opcode, 1);
|
||||
effective_address_[0] = calculate_effective_address(instruction, instruction_opcode_, 0);
|
||||
effective_address_[1] = calculate_effective_address(instruction, instruction_opcode_, 1);
|
||||
operand_[0] = effective_address_[0].value;
|
||||
operand_[1] = effective_address_[1].value;
|
||||
|
||||
@ -578,6 +629,7 @@ void Executor<model, BusHandler>::movem_toR(Preinstruction instruction, uint32_t
|
||||
#undef sp
|
||||
#undef Dn
|
||||
#undef An
|
||||
#undef AccessException
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1480,6 +1480,7 @@
|
||||
4B7C6819275196E8001671EC /* MouseJoystick.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MouseJoystick.hpp; sourceTree = "<group>"; };
|
||||
4B7C681C2751A104001671EC /* Bitplanes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Bitplanes.cpp; sourceTree = "<group>"; };
|
||||
4B7C681D2751A104001671EC /* Bitplanes.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Bitplanes.hpp; sourceTree = "<group>"; };
|
||||
4B7C79FE282AFA9B002D6C0B /* ExceptionVectors.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ExceptionVectors.hpp; sourceTree = "<group>"; };
|
||||
4B7F188C2154825D00388727 /* MasterSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MasterSystem.cpp; sourceTree = "<group>"; };
|
||||
4B7F188D2154825D00388727 /* MasterSystem.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MasterSystem.hpp; sourceTree = "<group>"; };
|
||||
4B7F1895215486A100388727 /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = "<group>"; };
|
||||
@ -3196,6 +3197,7 @@
|
||||
children = (
|
||||
4B79629F2819681F008130F9 /* Decoder.cpp */,
|
||||
4B79629E2819681F008130F9 /* Decoder.hpp */,
|
||||
4B7C79FE282AFA9B002D6C0B /* ExceptionVectors.hpp */,
|
||||
4BB5B99C281C805300522DA9 /* Executor.hpp */,
|
||||
4B79629C2819681F008130F9 /* Instruction.hpp */,
|
||||
4B79629D2819681F008130F9 /* Model.hpp */,
|
||||
|
Loading…
x
Reference in New Issue
Block a user