1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-06 01:28:57 +00:00

Implement CHK, and therefore the standard exception pattern.

This commit is contained in:
Thomas Harte 2022-05-19 16:27:39 -04:00
parent eeb6a088b8
commit 6c2eee0e44
2 changed files with 139 additions and 26 deletions

View File

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

View File

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