mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-30 23:29:08 +00:00
Implement CHK, and therefore the standard exception pattern.
This commit is contained in:
parent
eeb6a088b8
commit
6c2eee0e44
@ -12,6 +12,8 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include "../../../InstructionSets/M68k/ExceptionVectors.hpp"
|
||||||
|
|
||||||
namespace CPU {
|
namespace CPU {
|
||||||
namespace MC68000Mk2 {
|
namespace MC68000Mk2 {
|
||||||
|
|
||||||
@ -31,6 +33,9 @@ enum ExecutionState: int {
|
|||||||
StoreOperand,
|
StoreOperand,
|
||||||
StoreOperand_l,
|
StoreOperand_l,
|
||||||
|
|
||||||
|
StandardException,
|
||||||
|
BusOrAddressErrorException,
|
||||||
|
|
||||||
// Specific addressing mode fetches.
|
// Specific addressing mode fetches.
|
||||||
|
|
||||||
FetchAddressRegisterIndirect_bw,
|
FetchAddressRegisterIndirect_bw,
|
||||||
@ -70,6 +75,11 @@ enum ExecutionState: int {
|
|||||||
MOVEwAddressRegisterIndirectWithPostincrement,
|
MOVEwAddressRegisterIndirectWithPostincrement,
|
||||||
|
|
||||||
SABCD_PreDec,
|
SABCD_PreDec,
|
||||||
|
|
||||||
|
CHK,
|
||||||
|
CHK_no_trap,
|
||||||
|
CHK_was_over,
|
||||||
|
CHK_was_under,
|
||||||
};
|
};
|
||||||
|
|
||||||
// MARK: - The state machine.
|
// MARK: - The state machine.
|
||||||
@ -240,6 +250,47 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
Prefetch(); // np
|
Prefetch(); // np
|
||||||
MoveToState(Decode);
|
MoveToState(Decode);
|
||||||
|
|
||||||
|
// Perform a 'standard' exception, i.e. a Group 1 or 2.
|
||||||
|
BeginState(StandardException):
|
||||||
|
captured_status_.w = status_.status();
|
||||||
|
|
||||||
|
// Switch to supervisor mode.
|
||||||
|
status_.is_supervisor = true;
|
||||||
|
status_.trace_flag = 0;
|
||||||
|
did_update_status();
|
||||||
|
|
||||||
|
SetupDataAccess(0, Microcycle::SelectWord);
|
||||||
|
SetDataAddress(registers_[15].l);
|
||||||
|
|
||||||
|
// Push status and current program counter.
|
||||||
|
// Write order is wacky here, but I think it's correct.
|
||||||
|
registers_[15].l -= 6;
|
||||||
|
Access(captured_status_); // ns
|
||||||
|
|
||||||
|
registers_[15].l += 4;
|
||||||
|
Access(instruction_address_.low); // ns
|
||||||
|
|
||||||
|
registers_[15].l -= 2;
|
||||||
|
Access(instruction_address_.high); // nS
|
||||||
|
|
||||||
|
registers_[15].l -= 2;
|
||||||
|
|
||||||
|
// Grab new program counter.
|
||||||
|
SetupDataAccess(Microcycle::Read, Microcycle::SelectWord);
|
||||||
|
SetDataAddress(temporary_address_);
|
||||||
|
|
||||||
|
temporary_address_ = exception_vector_ << 2;
|
||||||
|
Access(program_counter_.high); // nV
|
||||||
|
|
||||||
|
temporary_address_ += 2;
|
||||||
|
Access(program_counter_.low); // nv
|
||||||
|
|
||||||
|
// Populate the prefetch queue.
|
||||||
|
Prefetch(); // np
|
||||||
|
IdleBus(1); // n
|
||||||
|
Prefetch(); // np
|
||||||
|
MoveToState(Decode);
|
||||||
|
|
||||||
// Inspect the prefetch queue in order to decode the next instruction,
|
// Inspect the prefetch queue in order to decode the next instruction,
|
||||||
// and segue into the fetching of operands.
|
// and segue into the fetching of operands.
|
||||||
BeginState(Decode):
|
BeginState(Decode):
|
||||||
@ -247,13 +298,13 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
|
|
||||||
opcode_ = prefetch_.high.w;
|
opcode_ = prefetch_.high.w;
|
||||||
instruction_ = decoder_.decode(opcode_);
|
instruction_ = decoder_.decode(opcode_);
|
||||||
instruction_address_ = program_counter_.l - 4;
|
instruction_address_.l = program_counter_.l - 4;
|
||||||
|
|
||||||
// TODO: check for privilege and unrecognised instructions.
|
// TODO: check for privilege and unrecognised instructions.
|
||||||
|
|
||||||
// Signal the bus handler if requested.
|
// Signal the bus handler if requested.
|
||||||
if constexpr (signal_will_perform) {
|
if constexpr (signal_will_perform) {
|
||||||
bus_handler_.will_perform(instruction_address_, opcode_);
|
bus_handler_.will_perform(instruction_address_.l, opcode_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the first parameter is next fetched.
|
// Ensure the first parameter is next fetched.
|
||||||
@ -298,6 +349,21 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Duplicate(NEGb, NEGXb) Duplicate(NOTb, NEGXb)
|
||||||
|
StdCASE(NEGXb, perform_state_ = Perform_np);
|
||||||
|
|
||||||
|
Duplicate(NEGw, NEGXw) Duplicate(NOTw, NEGXw)
|
||||||
|
StdCASE(NEGXw, perform_state_ = Perform_np);
|
||||||
|
|
||||||
|
Duplicate(NEGl, NEGXl) Duplicate(NOTl, NEGXl)
|
||||||
|
StdCASE(NEGXl,
|
||||||
|
if(instruction_.mode(0) == Mode::DataRegisterDirect) {
|
||||||
|
perform_state_ = Perform_np_n;
|
||||||
|
} else {
|
||||||
|
perform_state_ = Perform_np;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
StdCASE(SWAP, perform_state_ = Perform_np);
|
StdCASE(SWAP, perform_state_ = Perform_np);
|
||||||
StdCASE(EXG, perform_state_ = Perform_np_n);
|
StdCASE(EXG, perform_state_ = Perform_np_n);
|
||||||
|
|
||||||
@ -351,6 +417,8 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
MoveToState(SABCD_PreDec);
|
MoveToState(SABCD_PreDec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StdCASE(CHK, perform_state_ = CHK);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
@ -563,7 +631,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
//
|
//
|
||||||
BeginState(FetchProgramCounterIndirectWithDisplacement_bw):
|
BeginState(FetchProgramCounterIndirectWithDisplacement_bw):
|
||||||
effective_address_[next_operand_] =
|
effective_address_[next_operand_] =
|
||||||
instruction_address_ + 2 +
|
instruction_address_.l + 2 +
|
||||||
int16_t(prefetch_.w);
|
int16_t(prefetch_.w);
|
||||||
SetDataAddress(effective_address_[next_operand_]);
|
SetDataAddress(effective_address_[next_operand_]);
|
||||||
|
|
||||||
@ -573,7 +641,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
|
|
||||||
BeginState(FetchProgramCounterIndirectWithDisplacement_l):
|
BeginState(FetchProgramCounterIndirectWithDisplacement_l):
|
||||||
effective_address_[next_operand_] =
|
effective_address_[next_operand_] =
|
||||||
instruction_address_ + 2 +
|
instruction_address_.l + 2 +
|
||||||
int16_t(prefetch_.w);
|
int16_t(prefetch_.w);
|
||||||
SetDataAddress(effective_address_[next_operand_]);
|
SetDataAddress(effective_address_[next_operand_]);
|
||||||
|
|
||||||
@ -617,7 +685,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
// ProgramCounterIndirectWithIndex8bitDisplacement
|
// ProgramCounterIndirectWithIndex8bitDisplacement
|
||||||
//
|
//
|
||||||
BeginState(FetchProgramCounterIndirectWithIndex8bitDisplacement_bw):
|
BeginState(FetchProgramCounterIndirectWithIndex8bitDisplacement_bw):
|
||||||
effective_address_[next_operand_] = d8Xn(instruction_address_ + 2);
|
effective_address_[next_operand_] = d8Xn(instruction_address_.l + 2);
|
||||||
SetDataAddress(effective_address_[next_operand_]);
|
SetDataAddress(effective_address_[next_operand_]);
|
||||||
|
|
||||||
IdleBus(1); // n
|
IdleBus(1); // n
|
||||||
@ -626,7 +694,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
MoveToNextOperand(FetchOperand_bw);
|
MoveToNextOperand(FetchOperand_bw);
|
||||||
|
|
||||||
BeginState(FetchProgramCounterIndirectWithIndex8bitDisplacement_l):
|
BeginState(FetchProgramCounterIndirectWithIndex8bitDisplacement_l):
|
||||||
effective_address_[next_operand_] = d8Xn(instruction_address_ + 2);;
|
effective_address_[next_operand_] = d8Xn(instruction_address_.l + 2);;
|
||||||
SetDataAddress(effective_address_[next_operand_]);
|
SetDataAddress(effective_address_[next_operand_]);
|
||||||
|
|
||||||
IdleBus(1); // n
|
IdleBus(1); // n
|
||||||
@ -808,11 +876,40 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
|
|
||||||
MoveToState(Decode);
|
MoveToState(Decode);
|
||||||
|
|
||||||
|
BeginState(CHK):
|
||||||
|
Prefetch(); // np
|
||||||
|
InstructionSet::M68k::perform<
|
||||||
|
InstructionSet::M68k::Model::M68000,
|
||||||
|
ProcessorBase,
|
||||||
|
InstructionSet::M68k::Operation::CHK
|
||||||
|
>(
|
||||||
|
instruction_, operand_[0], operand_[1], status_, *static_cast<ProcessorBase *>(this));
|
||||||
|
|
||||||
|
// Proper next state will have been set by the flow controller
|
||||||
|
// call-in; just allow dispatch to whatever it was.
|
||||||
|
break;
|
||||||
|
|
||||||
|
BeginState(CHK_no_trap):
|
||||||
|
IdleBus(3); // nn n
|
||||||
|
MoveToState(Decode);
|
||||||
|
|
||||||
|
BeginState(CHK_was_over):
|
||||||
|
IdleBus(2); // nn
|
||||||
|
instruction_address_.l = program_counter_.l - 4;
|
||||||
|
exception_vector_ = InstructionSet::M68k::Exception::CHK;
|
||||||
|
MoveToState(StandardException);
|
||||||
|
|
||||||
|
BeginState(CHK_was_under):
|
||||||
|
IdleBus(3); // n nn
|
||||||
|
instruction_address_.l = program_counter_.l - 4;
|
||||||
|
exception_vector_ = InstructionSet::M68k::Exception::CHK;
|
||||||
|
MoveToState(StandardException);
|
||||||
|
|
||||||
// Various states TODO.
|
// Various states TODO.
|
||||||
#define TODOState(x) \
|
#define TODOState(x) \
|
||||||
BeginState(x): [[fallthrough]];
|
BeginState(x): [[fallthrough]];
|
||||||
|
|
||||||
// TODOState(FetchImmediateData_l);
|
TODOState(BusOrAddressErrorException);
|
||||||
|
|
||||||
#undef TODOState
|
#undef TODOState
|
||||||
|
|
||||||
@ -845,6 +942,16 @@ void ProcessorBase::did_update_status() {
|
|||||||
is_supervisor_ = int(status_.is_supervisor);
|
is_supervisor_ = int(status_.is_supervisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessorBase::did_chk(bool was_under, bool was_over) {
|
||||||
|
if(was_over) {
|
||||||
|
state_ = CHK_was_over;
|
||||||
|
} else if(was_under) {
|
||||||
|
state_ = CHK_was_under;
|
||||||
|
} else {
|
||||||
|
state_ = CHK_no_trap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - External state.
|
// MARK: - External state.
|
||||||
|
|
||||||
template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
|
template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
|
||||||
|
@ -38,7 +38,7 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
|
|||||||
InstructionSet::M68k::Preinstruction instruction_;
|
InstructionSet::M68k::Preinstruction instruction_;
|
||||||
uint16_t opcode_;
|
uint16_t opcode_;
|
||||||
uint8_t operand_flags_;
|
uint8_t operand_flags_;
|
||||||
uint32_t instruction_address_;
|
SlicedInt32 instruction_address_;
|
||||||
|
|
||||||
// Register state.
|
// Register state.
|
||||||
InstructionSet::M68k::Status status_;
|
InstructionSet::M68k::Status status_;
|
||||||
@ -81,6 +81,12 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
|
|||||||
/// a data select).
|
/// a data select).
|
||||||
uint32_t temporary_address_ = 0;
|
uint32_t temporary_address_ = 0;
|
||||||
|
|
||||||
|
/// A record of the exception to trigger.
|
||||||
|
int exception_vector_ = 0;
|
||||||
|
|
||||||
|
/// Transient storage for exception processing.
|
||||||
|
SlicedInt16 captured_status_;
|
||||||
|
|
||||||
// Flow controller... all TODO.
|
// Flow controller... all TODO.
|
||||||
using Preinstruction = InstructionSet::M68k::Preinstruction;
|
using Preinstruction = InstructionSet::M68k::Preinstruction;
|
||||||
|
|
||||||
@ -91,28 +97,28 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
|
|||||||
|
|
||||||
template <typename IntT> void did_mulu(IntT) {}
|
template <typename IntT> void did_mulu(IntT) {}
|
||||||
template <typename IntT> void did_muls(IntT) {}
|
template <typename IntT> void did_muls(IntT) {}
|
||||||
void did_chk(bool, bool) {}
|
inline void did_chk(bool, bool);
|
||||||
void did_shift(int) {}
|
inline void did_shift(int) {}
|
||||||
template <bool did_overflow> void did_divu(uint32_t, uint32_t) {}
|
template <bool did_overflow> void did_divu(uint32_t, uint32_t) {}
|
||||||
template <bool did_overflow> void did_divs(int32_t, int32_t) {}
|
template <bool did_overflow> void did_divs(int32_t, int32_t) {}
|
||||||
void did_bit_op(int) {}
|
inline void did_bit_op(int) {}
|
||||||
inline void did_update_status();
|
inline void did_update_status();
|
||||||
template <typename IntT> void complete_bcc(bool, IntT) {}
|
template <typename IntT> void complete_bcc(bool, IntT) {}
|
||||||
void complete_dbcc(bool, bool, int16_t) {}
|
inline void complete_dbcc(bool, bool, int16_t) {}
|
||||||
void bsr(uint32_t) {}
|
inline void bsr(uint32_t) {}
|
||||||
void jsr(uint32_t) {}
|
inline void jsr(uint32_t) {}
|
||||||
void jmp(uint32_t) {}
|
inline void jmp(uint32_t) {}
|
||||||
void rtr() {}
|
inline void rtr() {}
|
||||||
void rte() {}
|
inline void rte() {}
|
||||||
void rts() {}
|
inline void rts() {}
|
||||||
void stop() {}
|
inline void stop() {}
|
||||||
void reset() {}
|
inline void reset() {}
|
||||||
void link(Preinstruction, uint32_t) {}
|
inline void link(Preinstruction, uint32_t) {}
|
||||||
void unlink(uint32_t &) {}
|
inline void unlink(uint32_t &) {}
|
||||||
void pea(uint32_t) {}
|
inline void pea(uint32_t) {}
|
||||||
void move_to_usp(uint32_t) {}
|
inline void move_to_usp(uint32_t) {}
|
||||||
void move_from_usp(uint32_t &) {}
|
inline void move_from_usp(uint32_t &) {}
|
||||||
void tas(Preinstruction, uint32_t) {}
|
inline void tas(Preinstruction, uint32_t) {}
|
||||||
template <typename IntT> void movep(Preinstruction, uint32_t, uint32_t) {}
|
template <typename IntT> void movep(Preinstruction, uint32_t, uint32_t) {}
|
||||||
template <typename IntT> void movem_toM(Preinstruction, uint32_t, uint32_t) {}
|
template <typename IntT> void movem_toM(Preinstruction, uint32_t, uint32_t) {}
|
||||||
template <typename IntT> void movem_toR(Preinstruction, uint32_t, uint32_t) {}
|
template <typename IntT> void movem_toR(Preinstruction, uint32_t, uint32_t) {}
|
||||||
|
Loading…
Reference in New Issue
Block a user