mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-22 11:29:20 +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 <cstdio>
|
||||
|
||||
#include "../../../InstructionSets/M68k/ExceptionVectors.hpp"
|
||||
|
||||
namespace CPU {
|
||||
namespace MC68000Mk2 {
|
||||
|
||||
@ -31,6 +33,9 @@ enum ExecutionState: int {
|
||||
StoreOperand,
|
||||
StoreOperand_l,
|
||||
|
||||
StandardException,
|
||||
BusOrAddressErrorException,
|
||||
|
||||
// Specific addressing mode fetches.
|
||||
|
||||
FetchAddressRegisterIndirect_bw,
|
||||
@ -70,6 +75,11 @@ enum ExecutionState: int {
|
||||
MOVEwAddressRegisterIndirectWithPostincrement,
|
||||
|
||||
SABCD_PreDec,
|
||||
|
||||
CHK,
|
||||
CHK_no_trap,
|
||||
CHK_was_over,
|
||||
CHK_was_under,
|
||||
};
|
||||
|
||||
// MARK: - The state machine.
|
||||
@ -240,6 +250,47 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
Prefetch(); // np
|
||||
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,
|
||||
// and segue into the fetching of operands.
|
||||
BeginState(Decode):
|
||||
@ -247,13 +298,13 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
|
||||
opcode_ = prefetch_.high.w;
|
||||
instruction_ = decoder_.decode(opcode_);
|
||||
instruction_address_ = program_counter_.l - 4;
|
||||
instruction_address_.l = program_counter_.l - 4;
|
||||
|
||||
// TODO: check for privilege and unrecognised instructions.
|
||||
|
||||
// Signal the bus handler if requested.
|
||||
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.
|
||||
@ -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(EXG, perform_state_ = Perform_np_n);
|
||||
|
||||
@ -351,6 +417,8 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
MoveToState(SABCD_PreDec);
|
||||
}
|
||||
|
||||
StdCASE(CHK, perform_state_ = CHK);
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
@ -563,7 +631,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
//
|
||||
BeginState(FetchProgramCounterIndirectWithDisplacement_bw):
|
||||
effective_address_[next_operand_] =
|
||||
instruction_address_ + 2 +
|
||||
instruction_address_.l + 2 +
|
||||
int16_t(prefetch_.w);
|
||||
SetDataAddress(effective_address_[next_operand_]);
|
||||
|
||||
@ -573,7 +641,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
|
||||
BeginState(FetchProgramCounterIndirectWithDisplacement_l):
|
||||
effective_address_[next_operand_] =
|
||||
instruction_address_ + 2 +
|
||||
instruction_address_.l + 2 +
|
||||
int16_t(prefetch_.w);
|
||||
SetDataAddress(effective_address_[next_operand_]);
|
||||
|
||||
@ -617,7 +685,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
// ProgramCounterIndirectWithIndex8bitDisplacement
|
||||
//
|
||||
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_]);
|
||||
|
||||
IdleBus(1); // n
|
||||
@ -626,7 +694,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
MoveToNextOperand(FetchOperand_bw);
|
||||
|
||||
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_]);
|
||||
|
||||
IdleBus(1); // n
|
||||
@ -808,11 +876,40 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
||||
|
||||
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.
|
||||
#define TODOState(x) \
|
||||
BeginState(x): [[fallthrough]];
|
||||
|
||||
// TODOState(FetchImmediateData_l);
|
||||
TODOState(BusOrAddressErrorException);
|
||||
|
||||
#undef TODOState
|
||||
|
||||
@ -845,6 +942,16 @@ void ProcessorBase::did_update_status() {
|
||||
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.
|
||||
|
||||
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_;
|
||||
uint16_t opcode_;
|
||||
uint8_t operand_flags_;
|
||||
uint32_t instruction_address_;
|
||||
SlicedInt32 instruction_address_;
|
||||
|
||||
// Register state.
|
||||
InstructionSet::M68k::Status status_;
|
||||
@ -81,6 +81,12 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
|
||||
/// a data select).
|
||||
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.
|
||||
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_muls(IntT) {}
|
||||
void did_chk(bool, bool) {}
|
||||
void did_shift(int) {}
|
||||
inline void did_chk(bool, bool);
|
||||
inline void did_shift(int) {}
|
||||
template <bool did_overflow> void did_divu(uint32_t, uint32_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();
|
||||
template <typename IntT> void complete_bcc(bool, IntT) {}
|
||||
void complete_dbcc(bool, bool, int16_t) {}
|
||||
void bsr(uint32_t) {}
|
||||
void jsr(uint32_t) {}
|
||||
void jmp(uint32_t) {}
|
||||
void rtr() {}
|
||||
void rte() {}
|
||||
void rts() {}
|
||||
void stop() {}
|
||||
void reset() {}
|
||||
void link(Preinstruction, uint32_t) {}
|
||||
void unlink(uint32_t &) {}
|
||||
void pea(uint32_t) {}
|
||||
void move_to_usp(uint32_t) {}
|
||||
void move_from_usp(uint32_t &) {}
|
||||
void tas(Preinstruction, uint32_t) {}
|
||||
inline void complete_dbcc(bool, bool, int16_t) {}
|
||||
inline void bsr(uint32_t) {}
|
||||
inline void jsr(uint32_t) {}
|
||||
inline void jmp(uint32_t) {}
|
||||
inline void rtr() {}
|
||||
inline void rte() {}
|
||||
inline void rts() {}
|
||||
inline void stop() {}
|
||||
inline void reset() {}
|
||||
inline void link(Preinstruction, uint32_t) {}
|
||||
inline void unlink(uint32_t &) {}
|
||||
inline void pea(uint32_t) {}
|
||||
inline void move_to_usp(uint32_t) {}
|
||||
inline void move_from_usp(uint32_t &) {}
|
||||
inline void tas(Preinstruction, 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_toR(Preinstruction, uint32_t, uint32_t) {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user