1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Fix bus/address error exception frame: order and contents.

This commit is contained in:
Thomas Harte 2022-06-03 08:27:49 -04:00
parent 10b9b13673
commit 6fcaf3571e

View File

@ -328,6 +328,12 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
exception_vector_ = x; \
MoveToStateSpecific(StandardException);
// Copies the current program counter, adjusted to allow for the prefetch queue,
// into the instruction_address_ latch, which is the source of the value written
// during exceptions.
#define ReloadInstructionAddress() \
instruction_address_.l = program_counter_.l - 4
using Mode = InstructionSet::M68k::AddressingMode;
// Otherwise continue for all time, until back in debt.
@ -429,11 +435,11 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// So the below is a cross-your-fingers guess based on the constraints
// that the information writen, from lowest address to highest is:
//
// R/W, I/N, function code word; [at -2]
// access address; [-6]
// R/W, I/N, function code word; [at -14]
// access address; [-12]
// instruction register; [-8]
// status register; [-10]
// program counter. [-14]
// status register; [-6]
// program counter. [-4]
//
// With the instruction register definitely being written before the
// function code word.
@ -444,11 +450,12 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
//
// So, based on the hoopy ordering of a standard exception, maybe:
//
// 1) status register;
// 2) program counter;
// 3) instruction register;
// 4) function code;
// 5) access address?
// 1) program counter low;
// 2) captured state;
// 3) program counter high;
// 4) instruction register;
// 5) function code;
// 6) access address?
IdleBus(2);
@ -460,33 +467,49 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
SetupDataAccess(0, Microcycle::SelectWord);
SetDataAddress(registers_[15].l);
registers_[15].l -= 10;
Access(captured_status_); // ns
temporary_address_.l = program_counter_.l;
// Guess: the written program counter is adjusted to discount the prefetch queue.
// COMPLETE GUESS.
temporary_address_.l = program_counter_.l - 4;
registers_[15].l -= 2;
Access(temporary_address_.low); // ns
Access(temporary_address_.low); // ns [pc.l]
registers_[15].l -= 2;
Access(temporary_address_.high); // nS
registers_[15].l -= 4;
Access(captured_status_); // ns [sr]
registers_[15].l += 6;
registers_[15].l += 2;
Access(temporary_address_.high); // nS [pc.h]
registers_[15].l -= 4;
temporary_value_.w = opcode_;
Access(temporary_value_.low); // ns
Access(temporary_value_.low); // ns [instruction register]
// TODO: construct the function code.
temporary_value_.w = (temporary_value_.w & ~31);
// Construct the function code; which is:
//
// b4: 1 = was a read; 0 = was a write;
// b3: 0 = was reading an instruction; 1 = wasn't;
// b2b0: the regular 68000 function code;
// [all other bits]: left over from the instruction register write, above.
//
// I'm unable to come up with a reason why the function code isn't duplicative
// of b3, but given the repetition of supervisor state which is also in the
// captured status register I guess maybe it is just duplicative.
temporary_value_.w =
(temporary_value_.w & ~31) |
((bus_error_.operation & Microcycle::Read) ? 0x10 : 0x00) |
((bus_error_.operation & Microcycle::IsProgram) ? 0x08 : 0x00) |
((bus_error_.operation & Microcycle::IsProgram) ? 0x02 : 0x01) |
((captured_status_.w & InstructionSet::M68k::ConditionCode::Supervisor) ? 0x04 : 0x00);
registers_[15].l += 6;
Access(temporary_value_.low); // ns
registers_[15].l -= 6;
Access(temporary_value_.low); // ns [function code]
temporary_address_.l = *bus_error_.address;
registers_[15].l -= 2;
Access(temporary_value_.low); // ns
registers_[15].l += 4;
Access(temporary_address_.low); // ns [error address.l]
registers_[15].l -= 2;
Access(temporary_value_.high); // nS
registers_[15].l -= 8;
Access(temporary_address_.high); // nS [error address.h]
registers_[15].l -= 2;
// Grab new program counter.
SetupDataAccess(Microcycle::Read, Microcycle::SelectWord);
@ -502,7 +525,6 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
Prefetch(); // np
IdleBus(1); // n
Prefetch(); // np
MoveToStateSpecific(Decode);
// Acknowledge an interrupt, thereby obtaining an exception vector,
@ -521,7 +543,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// Push low part of program counter.
registers_[15].l -= 2;
Access(instruction_address_.low); // ns
Access(instruction_address_.low); // ns
// Do the interrupt cycle, to obtain a vector.
temporary_address_.l = 0xffff'fff1 | uint32_t(captured_interrupt_level_ << 1);
@ -536,7 +558,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// TODO: if bus error is set, treat interrupt as spurious.
IdleBus(3); // n- n
IdleBus(3); // n- n
// Do the rest of the stack work.
SetupDataAccess(0, Microcycle::SelectWord);
@ -554,10 +576,10 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
SetDataAddress(temporary_address_.l);
temporary_address_.l = uint32_t(temporary_value_.w << 2);
Access(program_counter_.high); // nV
Access(program_counter_.high); // nV
temporary_address_.l += 2;
Access(program_counter_.low); // nv
Access(program_counter_.low); // nv
// Populate the prefetch queue.
Prefetch(); // np
@ -571,7 +593,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
CheckOverrun();
// Capture the address of the next instruction.
instruction_address_.l = program_counter_.l - 4;
ReloadInstructionAddress();
// Head off into an interrupt if one is found.
if(captured_interrupt_level_ > status_.interrupt_level) {
@ -1771,12 +1793,12 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
BeginState(CHK_was_over):
IdleBus(2); // nn
instruction_address_.l = program_counter_.l - 4;
ReloadInstructionAddress();
RaiseException(InstructionSet::M68k::Exception::CHK);
BeginState(CHK_was_under):
IdleBus(3); // n nn
instruction_address_.l = program_counter_.l - 4;
ReloadInstructionAddress();
RaiseException(InstructionSet::M68k::Exception::CHK);
//
@ -2485,6 +2507,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
#undef CheckOverrun
#undef Spend
#undef ConsiderExit
#undef ReloadInstructionAddress
}