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);