From 01e93ba916c831e730d1f76a973fdc8478673adc Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Tue, 24 May 2022 15:42:50 -0400
Subject: [PATCH] Make an attempt at bus/address error.

---
 .../Implementation/68000Mk2Implementation.hpp | 102 +++++++++++++++---
 .../Implementation/68000Mk2Storage.hpp        |   3 +
 2 files changed, 93 insertions(+), 12 deletions(-)

diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp
index cacfbb2cd..54fe60b00 100644
--- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp
+++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp
@@ -17,7 +17,7 @@
 namespace CPU {
 namespace MC68000Mk2 {
 
-// TODO: obeyance of the trace flag, the address/bus error exception.
+// TODO: obeyance of the trace flag.
 
 /// States for the state machine which are named by
 /// me for their purpose rather than automatically by file position.
@@ -270,6 +270,8 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
 	//	(2) run for the next 10-cycle window.
 #define CompleteAccess(x)												\
 	if(berr_ || (*x.address & (x.operation >> 1) & 1)) {				\
+		bus_error_ = x;													\
+		exception_vector_ = berr_ ? InstructionSet::M68k::AccessFault : InstructionSet::M68k::AddressError;	\
 		MoveToStateSpecific(BusOrAddressErrorException);				\
 	}																	\
 	if(vpa_) {															\
@@ -375,9 +377,10 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
 		BeginState(StandardException):
 			captured_status_.w = status_.status();
 
-			// Switch to supervisor mode.
+			// Switch to supervisor mode, disable interrupts.
 			status_.is_supervisor = true;
 			status_.trace_flag = 0;
+			status_.interrupt_level = 7;
 			did_update_status();
 
 			SetupDataAccess(0, Microcycle::SelectWord);
@@ -412,6 +415,91 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
 			Prefetch();			// np
 		MoveToStateSpecific(Decode);
 
+		BeginState(BusOrAddressErrorException):
+			// "The microcode pushes the stack frame in a non consecutive order"
+			// per Ijor's document, but little further information is given.
+			//
+			// 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]
+			//	instruction register;				[-8]
+			//	status register;					[-10]
+			//	program counter.					[-14]
+			//
+			// With the instruction register definitely being written before the
+			// function code word.
+			//
+			// And the documented bus pattern is:
+			//
+			// nn ns ns nS ns ns ns nS nV nv np  n np
+			//
+			// 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?
+
+			captured_status_.w = status_.status();
+			IdleBus(2);
+
+			// Switch to supervisor mode, disable interrupts.
+			status_.is_supervisor = true;
+			status_.trace_flag = 0;
+			status_.interrupt_level = 7;
+			did_update_status();
+
+			SetupDataAccess(0, Microcycle::SelectWord);
+			SetDataAddress(registers_[15].l);
+
+			registers_[15].l -= 10;
+			Access(captured_status_);			// ns
+
+			temporary_address_.l = program_counter_.l;
+			registers_[15].l -= 2;
+			Access(temporary_address_.low);		// ns
+
+			registers_[15].l -= 2;
+			Access(temporary_address_.high);	// nS
+
+			registers_[15].l += 6;
+			temporary_value_.w = opcode_;
+			Access(temporary_value_.low);		// ns
+
+			// TODO: construct the function code.
+			temporary_value_.w = (temporary_value_.w & ~31);
+
+			registers_[15].l += 6;
+			Access(temporary_value_.low);		// ns
+
+			temporary_address_.l = *bus_error_.address;
+			registers_[15].l -= 2;
+			Access(temporary_value_.low);		// ns
+
+			registers_[15].l -= 2;
+			Access(temporary_value_.high);		// nS
+			registers_[15].l -= 8;
+
+			// Grab new program counter.
+			SetupDataAccess(Microcycle::Read, Microcycle::SelectWord);
+			SetDataAddress(temporary_address_.l);
+
+			temporary_address_.l = uint32_t(exception_vector_ << 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);
+
 		// Acknowledge an interrupt, thereby obtaining an exception vector,
 		// and do the exception.
 		BeginState(DoInterrupt):
@@ -2292,16 +2380,6 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
 			exception_vector_ = InstructionSet::M68k::Exception::TRAPV;
 		MoveToStateSpecific(StandardException);
 
-		//
-		// Various states TODO.
-		//
-#define TODOState(x)	\
-		BeginState(x): [[fallthrough]];
-
-		BeginState(BusOrAddressErrorException):
-			assert(false);
-		MoveToStateSpecific(Decode);
-
 #undef TODOState
 
 		default:
diff --git a/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp b/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp
index 25ad1e8bd..35674e088 100644
--- a/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp
+++ b/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp
@@ -136,6 +136,9 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
 	/// determine the size of the bus operation.
 	Microcycle::OperationT select_flag_ = 0;
 
+	// Captured bus/address-error state.
+	Microcycle bus_error_;
+
 	// Flow controller methods implemented.
 	using Preinstruction = InstructionSet::M68k::Preinstruction;
 	template <typename IntT> void did_mulu(IntT);