mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-15 20:31:36 +00:00
Fix bus/address error exception frame: order and contents.
This commit is contained in:
parent
10b9b13673
commit
6fcaf3571e
@ -328,6 +328,12 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
exception_vector_ = x; \
|
exception_vector_ = x; \
|
||||||
MoveToStateSpecific(StandardException);
|
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;
|
using Mode = InstructionSet::M68k::AddressingMode;
|
||||||
|
|
||||||
// Otherwise continue for all time, until back in debt.
|
// 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
|
// So the below is a cross-your-fingers guess based on the constraints
|
||||||
// that the information writen, from lowest address to highest is:
|
// that the information writen, from lowest address to highest is:
|
||||||
//
|
//
|
||||||
// R/W, I/N, function code word; [at -2]
|
// R/W, I/N, function code word; [at -14]
|
||||||
// access address; [-6]
|
// access address; [-12]
|
||||||
// instruction register; [-8]
|
// instruction register; [-8]
|
||||||
// status register; [-10]
|
// status register; [-6]
|
||||||
// program counter. [-14]
|
// program counter. [-4]
|
||||||
//
|
//
|
||||||
// With the instruction register definitely being written before the
|
// With the instruction register definitely being written before the
|
||||||
// function code word.
|
// 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:
|
// So, based on the hoopy ordering of a standard exception, maybe:
|
||||||
//
|
//
|
||||||
// 1) status register;
|
// 1) program counter low;
|
||||||
// 2) program counter;
|
// 2) captured state;
|
||||||
// 3) instruction register;
|
// 3) program counter high;
|
||||||
// 4) function code;
|
// 4) instruction register;
|
||||||
// 5) access address?
|
// 5) function code;
|
||||||
|
// 6) access address?
|
||||||
|
|
||||||
IdleBus(2);
|
IdleBus(2);
|
||||||
|
|
||||||
@ -460,33 +467,49 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
SetupDataAccess(0, Microcycle::SelectWord);
|
SetupDataAccess(0, Microcycle::SelectWord);
|
||||||
SetDataAddress(registers_[15].l);
|
SetDataAddress(registers_[15].l);
|
||||||
|
|
||||||
registers_[15].l -= 10;
|
// Guess: the written program counter is adjusted to discount the prefetch queue.
|
||||||
Access(captured_status_); // ns
|
// COMPLETE GUESS.
|
||||||
|
temporary_address_.l = program_counter_.l - 4;
|
||||||
temporary_address_.l = program_counter_.l;
|
|
||||||
registers_[15].l -= 2;
|
registers_[15].l -= 2;
|
||||||
Access(temporary_address_.low); // ns
|
Access(temporary_address_.low); // ns [pc.l]
|
||||||
|
|
||||||
registers_[15].l -= 2;
|
registers_[15].l -= 4;
|
||||||
Access(temporary_address_.high); // nS
|
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_;
|
temporary_value_.w = opcode_;
|
||||||
Access(temporary_value_.low); // ns
|
Access(temporary_value_.low); // ns [instruction register]
|
||||||
|
|
||||||
// TODO: construct the function code.
|
// Construct the function code; which is:
|
||||||
temporary_value_.w = (temporary_value_.w & ~31);
|
//
|
||||||
|
// b4: 1 = was a read; 0 = was a write;
|
||||||
|
// b3: 0 = was reading an instruction; 1 = wasn't;
|
||||||
|
// b2–b0: 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;
|
registers_[15].l -= 6;
|
||||||
Access(temporary_value_.low); // ns
|
Access(temporary_value_.low); // ns [function code]
|
||||||
|
|
||||||
temporary_address_.l = *bus_error_.address;
|
temporary_address_.l = *bus_error_.address;
|
||||||
registers_[15].l -= 2;
|
registers_[15].l += 4;
|
||||||
Access(temporary_value_.low); // ns
|
Access(temporary_address_.low); // ns [error address.l]
|
||||||
|
|
||||||
registers_[15].l -= 2;
|
registers_[15].l -= 2;
|
||||||
Access(temporary_value_.high); // nS
|
Access(temporary_address_.high); // nS [error address.h]
|
||||||
registers_[15].l -= 8;
|
registers_[15].l -= 2;
|
||||||
|
|
||||||
// Grab new program counter.
|
// Grab new program counter.
|
||||||
SetupDataAccess(Microcycle::Read, Microcycle::SelectWord);
|
SetupDataAccess(Microcycle::Read, Microcycle::SelectWord);
|
||||||
@ -502,7 +525,6 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
Prefetch(); // np
|
Prefetch(); // np
|
||||||
IdleBus(1); // n
|
IdleBus(1); // n
|
||||||
Prefetch(); // np
|
Prefetch(); // np
|
||||||
|
|
||||||
MoveToStateSpecific(Decode);
|
MoveToStateSpecific(Decode);
|
||||||
|
|
||||||
// Acknowledge an interrupt, thereby obtaining an exception vector,
|
// 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.
|
// Push low part of program counter.
|
||||||
registers_[15].l -= 2;
|
registers_[15].l -= 2;
|
||||||
Access(instruction_address_.low); // ns
|
Access(instruction_address_.low); // ns
|
||||||
|
|
||||||
// Do the interrupt cycle, to obtain a vector.
|
// Do the interrupt cycle, to obtain a vector.
|
||||||
temporary_address_.l = 0xffff'fff1 | uint32_t(captured_interrupt_level_ << 1);
|
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.
|
// 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.
|
// Do the rest of the stack work.
|
||||||
SetupDataAccess(0, Microcycle::SelectWord);
|
SetupDataAccess(0, Microcycle::SelectWord);
|
||||||
@ -554,10 +576,10 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
SetDataAddress(temporary_address_.l);
|
SetDataAddress(temporary_address_.l);
|
||||||
|
|
||||||
temporary_address_.l = uint32_t(temporary_value_.w << 2);
|
temporary_address_.l = uint32_t(temporary_value_.w << 2);
|
||||||
Access(program_counter_.high); // nV
|
Access(program_counter_.high); // nV
|
||||||
|
|
||||||
temporary_address_.l += 2;
|
temporary_address_.l += 2;
|
||||||
Access(program_counter_.low); // nv
|
Access(program_counter_.low); // nv
|
||||||
|
|
||||||
// Populate the prefetch queue.
|
// Populate the prefetch queue.
|
||||||
Prefetch(); // np
|
Prefetch(); // np
|
||||||
@ -571,7 +593,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
CheckOverrun();
|
CheckOverrun();
|
||||||
|
|
||||||
// Capture the address of the next instruction.
|
// Capture the address of the next instruction.
|
||||||
instruction_address_.l = program_counter_.l - 4;
|
ReloadInstructionAddress();
|
||||||
|
|
||||||
// Head off into an interrupt if one is found.
|
// Head off into an interrupt if one is found.
|
||||||
if(captured_interrupt_level_ > status_.interrupt_level) {
|
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):
|
BeginState(CHK_was_over):
|
||||||
IdleBus(2); // nn
|
IdleBus(2); // nn
|
||||||
instruction_address_.l = program_counter_.l - 4;
|
ReloadInstructionAddress();
|
||||||
RaiseException(InstructionSet::M68k::Exception::CHK);
|
RaiseException(InstructionSet::M68k::Exception::CHK);
|
||||||
|
|
||||||
BeginState(CHK_was_under):
|
BeginState(CHK_was_under):
|
||||||
IdleBus(3); // n nn
|
IdleBus(3); // n nn
|
||||||
instruction_address_.l = program_counter_.l - 4;
|
ReloadInstructionAddress();
|
||||||
RaiseException(InstructionSet::M68k::Exception::CHK);
|
RaiseException(InstructionSet::M68k::Exception::CHK);
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -2485,6 +2507,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
|
|||||||
#undef CheckOverrun
|
#undef CheckOverrun
|
||||||
#undef Spend
|
#undef Spend
|
||||||
#undef ConsiderExit
|
#undef ConsiderExit
|
||||||
|
#undef ReloadInstructionAddress
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user