1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-02 16:38:51 +00:00

Attempt interrupt support.

This commit is contained in:
Thomas Harte 2022-05-24 10:53:59 -04:00
parent 3a4fb81242
commit 3349bcaaed
3 changed files with 82 additions and 5 deletions

View File

@ -29,7 +29,7 @@ enum Exception {
FormatError = 14,
UninitialisedInterrupt = 15,
SpuriousInterrupt = 24,
InterruptAutovectorBase = 25,
InterruptAutovectorBase = 25, // This is the vector for interrupt level _1_.
TrapBase = 32,
FPBranchOrSetOnUnorderedCondition = 48,
FPInexactResult = 49,

View File

@ -44,6 +44,7 @@ enum ExecutionState: int {
StandardException,
BusOrAddressErrorException,
DoInterrupt,
// Specific addressing mode fetches.
//
@ -313,8 +314,9 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// Reads one futher word from the program counter and inserts it into
// the prefetch queue.
#define Prefetch() \
prefetch_.high = prefetch_.low; \
#define Prefetch() \
captured_interrupt_level_ = bus_interrupt_level_; \
prefetch_.high = prefetch_.low; \
ReadProgramWord(prefetch_.low)
using Mode = InstructionSet::M68k::AddressingMode;
@ -335,7 +337,11 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// Spin in place until an interrupt arrives.
BeginState(STOP):
assert(false); // TODO
IdleBus(1);
captured_interrupt_level_ = bus_interrupt_level_;
if(captured_interrupt_level_ > status_.interrupt_level) {
MoveToStateSpecific(DoInterrupt);
}
MoveToStateSpecific(STOP);
// Perform the RESET exception, which seeds the stack pointer and program
@ -410,14 +416,80 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
Prefetch(); // np
MoveToStateSpecific(Decode);
// Acknowledge an interrupt, thereby obtaining an exception vector,
// and do the exception.
BeginState(DoInterrupt):
IdleBus(3); // n nn
// Capture status and switch to supervisor mode.
captured_status_.w = status_.status();
status_.is_supervisor = true;
status_.trace_flag = 0;
did_update_status();
// Prepare for stack activity.
SetupDataAccess(0, Microcycle::SelectWord);
SetDataAddress(registers_[15].l);
// Push status.
registers_[15].l -= 2;
Access(captured_status_); // ns
// Do the interrupt cycle, to obtain a vector.
temporary_address_.l = captured_interrupt_level_;
SetupDataAccess(0, Microcycle::InterruptAcknowledge);
SetDataAddress(temporary_address_.l);
Access(temporary_value_.low); // ni
// If VPA is set, autovector.
if(vpa_) {
temporary_value_.w = InstructionSet::M68k::Exception::InterruptAutovectorBase - 1 + captured_interrupt_level_;
}
IdleBus(3); // n- n
// Do the rest of the stack work.
SetupDataAccess(0, Microcycle::SelectWord);
SetDataAddress(registers_[15].l);
registers_[15].l -= 2;
Access(instruction_address_.high); // ns
registers_[15].l -= 2;
Access(instruction_address_.low); // nS
// Grab new program counter.
SetupDataAccess(Microcycle::Read, Microcycle::SelectWord);
SetDataAddress(temporary_address_.l);
temporary_address_.l <<= 2;
Access(program_counter_.high); // nV
temporary_address_.l += 2;
Access(program_counter_.low); // nv
// Populate the prefetch queue.
Prefetch(); // np
IdleBus(1); // n
Prefetch(); // np
MoveToStateSpecific(Decode);
// Inspect the prefetch queue in order to decode the next instruction,
// and segue into the fetching of operands.
BeginState(Decode):
CheckOverrun();
// Capture the address of the next instruction.
instruction_address_.l = program_counter_.l - 4;
// Head off into an interrupt if one is found.
if(captured_interrupt_level_ > status_.interrupt_level) {
MoveToStateSpecific(DoInterrupt);
}
// Read and decode an opcode.
opcode_ = prefetch_.high.w;
instruction_ = decoder_.decode(opcode_);
instruction_address_.l = program_counter_.l - 4;
// Signal the bus handler if requested.
if constexpr (signal_will_perform) {

View File

@ -58,6 +58,11 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
/// Current input interrupt level.
int bus_interrupt_level_ = 0;
// I don't have great information on the 68000 interrupt latency; as a first
// guess, capture the bus interrupt level upon every prefetch, and use that for
// the inner-loop decision.
int captured_interrupt_level_ = 0;
/// Contains the prefetch queue; the most-recently fetched thing is the
/// low portion of this word, and the thing fetched before that has
/// proceeded to the high portion.