1
0
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:
Thomas Harte 2022-05-10 16:20:30 -04:00
parent 477979c275
commit ab8e1fdcbf
4 changed files with 125 additions and 14 deletions

View 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 */

View File

@ -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]; // D0D8, followed by A0A8.
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

View File

@ -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
}
}

View File

@ -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 */,