//
//  68000Implementation.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 10/03/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#define get_ccr() \
	(	\
		(carry_flag_ 	? 0x0001 : 0x0000) |	\
		(overflow_flag_	? 0x0002 : 0x0000) |	\
		(zero_result_	? 0x0000 : 0x0004) |	\
		(negative_flag_	? 0x0008 : 0x0000) |	\
		(extend_flag_	? 0x0010 : 0x0000)		\
	)

#define get_status() \
	uint16_t(	\
		get_ccr() |	\
		(interrupt_level_ << 8) |				\
		(trace_flag_ ? 0x8000 : 0x0000) |		\
		(is_supervisor_ << 13)					\
	)

#define set_ccr(x) \
	carry_flag_			= (x) & 0x0001;	\
	overflow_flag_		= (x) & 0x0002;	\
	zero_result_		= ((x) & 0x0004) ^ 0x0004;	\
	negative_flag_		= (x) & 0x0008;	\
	extend_flag_		= (x) & 0x0010;

#define set_status(x) \
	set_ccr(x)	\
	interrupt_level_ 	= ((x) >> 8) & 7;	\
	trace_flag_			= (x) & 0x8000;	\
	set_is_supervisor(!!(((x) >> 13) & 1));

#define get_bus_code()	\
	uint16_t(	\
		((active_step_->microcycle.operation & Microcycle::IsProgram) ? 0x02 : 0x01) |	\
		(is_supervisor_ << 2) |	\
		(active_program_ ? 0x08 : 0) |	\
		((active_step_->microcycle.operation & Microcycle::Read) ? 0x10 : 0) |	\
		(decoded_instruction_.full & 0xffe0)	\
	)

#define u_extend16(x)	uint32_t(int16_t(x))
#define u_extend8(x)	uint32_t(int8_t(x))
#define s_extend16(x)	int32_t(int16_t(x))
#define s_extend8(x)	int32_t(int8_t(x))

#define convert_to_bit_count_16(x)	\
	x = ((x & 0xaaaa) >> 1) + (x & 0x5555);	\
	x = ((x & 0xcccc) >> 2) + (x & 0x3333);	\
	x = ((x & 0xf0f0) >> 4) + (x & 0x0f0f);	\
	x = ((x & 0xff00) >> 8) + (x & 0x00ff);

// Sets the length of the next microcycle; if this is a debug build, also confirms
// that the microcycle being adjusted is the one that it's permissible to adjust.
#ifdef NDEBUG
#define set_next_microcycle_length(x)	\
	bus_program->microcycle.length = x
#else
#define set_next_microcycle_length(x)	\
	assert(bus_program->microcycle.is_resizeable);	\
	bus_program->microcycle.length = x
#endif

template <class T, bool dtack_is_implicit, bool signal_will_perform> void Processor<T, dtack_is_implicit, signal_will_perform>::run_for(HalfCycles duration) {
	const HalfCycles remaining_duration = duration + half_cycles_left_to_run_;

	// This loop counts upwards rather than downwards because it simplifies calculation of
	// E as and when required.
	HalfCycles cycles_run_for;
	while(cycles_run_for < remaining_duration) {
		/*
			PERFORM THE CURRENT BUS STEP'S MICROCYCLE.
		*/
			switch(execution_state_) {
				default:
				case ExecutionState::Executing:
					// Check for entry into the halted state.
					if(halt_ && active_step_[0].microcycle.operation & Microcycle::NewAddress) {
						execution_state_ = ExecutionState::Halted;
						continue;
					}

					if(active_step_->microcycle.data_select_active()) {
						// Check whether the processor needs to await DTack.
						if(!dtack_is_implicit && !dtack_ && !bus_error_) {
							execution_state_ = ExecutionState::WaitingForDTack;
							dtack_cycle_ = active_step_->microcycle;
							dtack_cycle_.length = HalfCycles(2);
							dtack_cycle_.operation &= ~(Microcycle::SelectByte | Microcycle::SelectWord);
							continue;
						}

						// Check for bus error.
						if(bus_error_ && !is_starting_interrupt_) {
							const auto offending_address = *active_step_->microcycle.address;
							active_program_ = nullptr;
							active_micro_op_ = long_exception_micro_ops_;
							populate_bus_error_steps(2, get_status(), get_bus_code(), offending_address);
							program_counter_.full -= 4;
							active_step_ = &all_bus_steps_[active_micro_op_->bus_program];
						}
					}

					// Check for an address error. Which I have assumed happens before the microcycle that
					// would nominate the new address.
					if(
						(active_step_[0].microcycle.operation & Microcycle::NewAddress) &&
						(active_step_[1].microcycle.operation & Microcycle::SelectWord) &&
						*active_step_->microcycle.address & 1) {
						const auto offending_address = *active_step_->microcycle.address;
						active_program_ = nullptr;
						active_micro_op_ = long_exception_micro_ops_;
						populate_bus_error_steps(3, get_status(), get_bus_code(), offending_address);
						program_counter_.full -= 4;
						active_step_ = &all_bus_steps_[active_micro_op_->bus_program];

						// TODO: the above is only correct prior to the final microcycle of an
						// instruction. If an exception occurs in the final microcycle then
						// the next instruction will already have moved into the current instruction
						// slot (decoded_instruction_ in my terms).

						// TODO: it's also not correct for a bus error that occurs during another exception.
					}

					// Perform the microcycle if it is of non-zero length. If this is an operation that
					// would normally strobe one of the data selects and VPA is active, it will also need
					// stretching.
					if(active_step_->microcycle.length != HalfCycles(0)) {
						if(is_peripheral_address_ && active_step_->microcycle.data_select_active()) {
							auto cycle_copy = active_step_->microcycle;
							cycle_copy.operation |= Microcycle::IsPeripheral;

							// Extend length by: (i) distance to next E low, plus (ii) difference between
							// current length and a whole E cycle.
							cycle_copy.length = HalfCycles(20);	// i.e. one E cycle in length.
							cycle_copy.length += (e_clock_phase_ + cycles_run_for) % 10;

							cycles_run_for +=
								cycle_copy.length +
								bus_handler_.perform_bus_operation(cycle_copy, is_supervisor_);
						} else {
							cycles_run_for +=
								active_step_->microcycle.length +
								bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
						}
					}

#ifdef LOG_TRACE
					if(should_log && !(active_step_->microcycle.operation & Microcycle::IsProgram)) {
						switch(active_step_->microcycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
							default: break;

							case Microcycle::SelectWord | Microcycle::Read:
								printf("[%08x -> %04x] ", *active_step_->microcycle.address, active_step_->microcycle.value->full);
							break;
							case Microcycle::SelectByte | Microcycle::Read:
								printf("[%08x -> %02x] ", *active_step_->microcycle.address, active_step_->microcycle.value->halves.low);
							break;
							case Microcycle::SelectWord:
								printf("{%04x -> %08x} ", active_step_->microcycle.value->full, *active_step_->microcycle.address);
							break;
							case Microcycle::SelectByte:
								printf("{%02x -> %08x} ", active_step_->microcycle.value->halves.low, *active_step_->microcycle.address);
							break;
						}
					}
#endif

					/*
						PERFORM THE BUS STEP'S ACTION.
					*/
						switch(active_step_->action) {
							default:
								std::cerr << "Unimplemented 68000 bus step action: " << int(active_step_->action) << std::endl;
								return;
							break;

							case BusStep::Action::None: break;

							case BusStep::Action::IncrementEffectiveAddress0:	effective_address_[0].full += 2;	break;
							case BusStep::Action::IncrementEffectiveAddress1:	effective_address_[1].full += 2;	break;
							case BusStep::Action::DecrementEffectiveAddress0:	effective_address_[0].full -= 2;	break;
							case BusStep::Action::DecrementEffectiveAddress1:	effective_address_[1].full -= 2;	break;
							case BusStep::Action::IncrementProgramCounter:		program_counter_.full += 2;			break;

							case BusStep::Action::AdvancePrefetch:
								prefetch_queue_.halves.high = prefetch_queue_.halves.low;

								// During prefetch advance seems to be the only time the interrupt inputs are sampled;
								// TODO: determine whether this really happens on *every* advance.
								if(bus_interrupt_level_ > interrupt_level_) {
									pending_interrupt_level_ = bus_interrupt_level_;
								}
							break;
						}

						// Move to the next bus step.
						++ active_step_;
				break;

				case ExecutionState::Stopped:
					// If an interrupt (TODO: or reset) has finally arrived that will be serviced,
					// exit the STOP.
					if(bus_interrupt_level_ > interrupt_level_) {
						pending_interrupt_level_ = bus_interrupt_level_;
						program_counter_.full += 4;	// Don't return to this stop.
						execution_state_ = ExecutionState::BeginInterrupt;
						continue;
					}

					// Otherwise continue being stopped.
					cycles_run_for +=
						stop_cycle_.length +
						bus_handler_.perform_bus_operation(stop_cycle_, is_supervisor_);
				continue;

				case ExecutionState::WaitingForDTack:
					// If DTack or bus error has been signalled, stop waiting.
					if(dtack_ || bus_error_) {
						execution_state_ = ExecutionState::Executing;
						continue;
					}

					// Otherwise, signal another cycle of wait.
					cycles_run_for +=
						dtack_cycle_.length +
						bus_handler_.perform_bus_operation(dtack_cycle_, is_supervisor_);
				continue;

				case ExecutionState::Halted:
					if(!halt_) {
						execution_state_ = ExecutionState::Executing;
						continue;
					}

					cycles_run_for +=
						stop_cycle_.length +
						bus_handler_.perform_bus_operation(stop_cycle_, is_supervisor_);
				continue;

				case ExecutionState::BeginInterrupt:
#ifdef LOG_TRACE
//					should_log = true;
#endif
					active_program_ = nullptr;
					active_micro_op_ = interrupt_micro_ops_;
					execution_state_ = ExecutionState::Executing;
					active_step_ = &all_bus_steps_[active_micro_op_->bus_program];
					is_starting_interrupt_ = true;
				break;
			}

		/*
			FIND THE NEXT MICRO-OP IF UNKNOWN.
		*/
			if(active_step_->is_terminal()) {
				while(true) {
					// If there are any more micro-operations available, just move onwards.
					if(active_micro_op_ && !active_micro_op_->is_terminal()) {
						++active_micro_op_;
					} else {
						// Either the micro-operations for this instruction have been exhausted, or
						// no instruction was ongoing. Either way, do a standard instruction operation.

						if(pending_interrupt_level_) {
							execution_state_ = ExecutionState::BeginInterrupt;
							break;
						}

						if(trace_flag_ && last_trace_flag_) {
							// The user has set the trace bit in the status register.
							active_program_ = nullptr;
							active_micro_op_ = short_exception_micro_ops_;
							populate_trap_steps(9, get_status());
							program_counter_.full -= 4;
						} else {
#ifdef LOG_TRACE
							if(should_log) {
								std::cout << std::setfill('0');
								std::cout << (extend_flag_ ? 'x' : '-') << (negative_flag_ ? 'n' : '-') << (zero_result_ ? '-' : 'z');
								std::cout << (overflow_flag_ ? 'v' : '-') << (carry_flag_ ? 'c' : '-') << '\t';
								std::cout << (is_supervisor_ ? 's' : 'u') << '\t';
								for(int c = 0; c < 8; ++ c) std::cout << "d" << c << ":" << std::setw(8) << data_[c].full << " ";
								for(int c = 0; c < 8; ++ c) std::cout << "a" << c << ":" << std::setw(8) << address_[c].full << " ";
								if(is_supervisor_) {
									std::cout << "usp:" << std::setw(8) << std::setfill('0') << stack_pointers_[0].full << " ";
								} else {
									std::cout << "ssp:" << std::setw(8) << std::setfill('0') << stack_pointers_[1].full << " ";
								}
								std::cout << '\n';
							}
#endif

							decoded_instruction_.full = prefetch_queue_.halves.high.full;

#ifndef NDEBUG
							/* Debugging feature: reset the effective addresses and data latches, so that it's
							more obvious if some of the instructions aren't properly feeding them. */
							effective_address_[0].full = effective_address_[1].full = source_bus_data_[0].full = destination_bus_data_[0].full = 0x12344321;
#endif

#ifdef LOG_TRACE
							if(should_log) {
								std::cout << std::hex << (program_counter_.full - 4) << ": " << std::setw(4) << decoded_instruction_.full << '\t';
							}
#endif

							if constexpr (signal_will_perform) {
								bus_handler_.will_perform(program_counter_.full - 4, decoded_instruction_.full);
							}

#ifdef LOG_TRACE
//							const uint32_t fetched_pc = (program_counter_.full - 4)&0xffffff;

//							should_log |= fetched_pc == 0x6d9c;
//							should_log = (fetched_pc >= 0x41806A && fetched_pc <= 0x418618);
//							should_log |= fetched_pc == 0x4012A2;
//							should_log &= fetched_pc != 0x4012AE;

//							should_log = (fetched_pc >= 0x408D66) && (fetched_pc <= 0x408D84);
#endif

							if(instructions[decoded_instruction_.full].micro_operations != std::numeric_limits<uint32_t>::max()) {
								if((instructions[decoded_instruction_.full].source_dest & 0x80) && !is_supervisor_) {
									// A privilege violation has been detected.
									active_program_ = nullptr;
									active_micro_op_ = short_exception_micro_ops_;
									populate_trap_steps(8, get_status());
								} else {
									// Standard instruction dispatch.
									active_program_ = &instructions[decoded_instruction_.full];
									active_micro_op_ = &all_micro_ops_[active_program_->micro_operations];
								}
							} else {
								// The opcode fetched isn't valid.
								active_program_ = nullptr;
								active_micro_op_ = short_exception_micro_ops_;

								// The location of the failed instruction is what should end up on the stack.
								program_counter_.full -= 4;

#ifdef LOG_TRACE
//								should_log = true;
#endif

								// The vector used depends on whether this is a vanilla unrecognised instruction,
								// or one on the A or F lines.
								switch(decoded_instruction_.full >> 12) {
									default:
										populate_trap_steps(4, get_status());
									break;
									case 0xa:
										populate_trap_steps(10, get_status());
									break;
									case 0xf:
										populate_trap_steps(11, get_status());
									break;
								}
							}
						}
						last_trace_flag_ = trace_flag_;
					}

					auto bus_program = &all_bus_steps_[active_micro_op_->bus_program];
					using int_type = decltype(active_micro_op_->action);
					switch(active_micro_op_->action) {
						default:
							std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << " within instruction " << decoded_instruction_.full <<  std::endl;
						break;

						case int_type(MicroOp::Action::None): break;

#define offset_pointer(x)		reinterpret_cast<RegisterPair32 *>(&reinterpret_cast<uint8_t *>(static_cast<ProcessorStorage *>(this))[x])
#define source()				offset_pointer(active_program_->source_offset)
#define source_address()		address_[(active_program_->source_dest >> 4) & 7]
#define destination()			offset_pointer(active_program_->destination_offset)
#define destination_address()	address_[active_program_->source_dest & 7]

						case int_type(MicroOp::Action::PerformOperation):
#define sub_overflow() ((result ^ destination) & (destination ^ source))
#define add_overflow() ((result ^ destination) & ~(destination ^ source))
							switch(active_program_->operation) {
								/*
									ABCD adds the lowest bytes form the source and destination using BCD arithmetic,
									obeying the extend flag.
								*/
								case Operation::ABCD: {
									// Pull out the two halves, for simplicity.
									const uint8_t source = source()->halves.low.halves.low;
									const uint8_t destination = destination()->halves.low.halves.low;

									// Perform the BCD add by evaluating the two nibbles separately.
									const int unadjusted_result = destination + source + (extend_flag_ ? 1 : 0);
									int result = (destination & 0xf) + (source & 0xf) + (extend_flag_ ? 1 : 0);
									if(result > 0x09) result += 0x06;
									result += (destination & 0xf0) + (source & 0xf0);
									if(result > 0x99) result += 0x60;

									// Set all flags essentially as if this were normal addition.
									zero_result_ |= result & 0xff;
									extend_flag_ = carry_flag_ = uint_fast32_t(result & ~0xff);
									negative_flag_ = result & 0x80;
									overflow_flag_ = ~unadjusted_result & result & 0x80;

									// Store the result.
									destination()->halves.low.halves.low = uint8_t(result);
								} break;

								// ADD and ADDA add two quantities, the latter sign extending and without setting any flags;
								// ADDQ and SUBQ act as ADD and SUB, but taking the second argument from the instruction code.
#define addop(a, b, x) 	a + b + (x ? 1 : 0)
#define subop(a, b, x) 	a - b - (x ? 1 : 0)
#define z_set(a, b)		a = b
#define z_or(a, b)		a |= b

#define addsubb(a, b, dest, op, overflow, x, zero_op)	\
	const int source = a;	\
	const int destination = b;	\
	const auto result = op(destination, source, x);	\
\
	dest = uint8_t(result);	\
	zero_op(zero_result_, dest);	\
	extend_flag_ = carry_flag_ = uint_fast32_t(result & ~0xff);	\
	negative_flag_ = result & 0x80;	\
	overflow_flag_ = overflow() & 0x80;

#define addsubw(a, b, dest, op, overflow, x, zero_op)	\
	const int source = a;	\
	const int destination = b;	\
	const auto result = op(destination, source, x);	\
\
	dest = uint16_t(result);	\
	zero_op(zero_result_, dest);	\
	extend_flag_ = carry_flag_ = uint_fast32_t(result & ~0xffff);	\
	negative_flag_ = result & 0x8000;	\
	overflow_flag_ = overflow() & 0x8000;

#define addsubl(a, b, dest, op, overflow, x, zero_op)	\
	const uint64_t source = a;	\
	const uint64_t destination = b;	\
	const auto result = op(destination, source, x);	\
\
	dest = uint32_t(result);	\
	zero_op(zero_result_, dest);	\
	extend_flag_ = carry_flag_ = uint_fast32_t(result >> 32);	\
	negative_flag_ = result & 0x80000000;	\
	overflow_flag_ = overflow() & 0x80000000;

#define addb(a, b, dest, x, z) addsubb(a, b, dest, addop, add_overflow, x, z)
#define subb(a, b, dest, x, z) addsubb(a, b, dest, subop, sub_overflow, x, z)
#define addw(a, b, dest, x, z) addsubw(a, b, dest, addop, add_overflow, x, z)
#define subw(a, b, dest, x, z) addsubw(a, b, dest, subop, sub_overflow, x, z)
#define addl(a, b, dest, x, z) addsubl(a, b, dest, addop, add_overflow, x, z)
#define subl(a, b, dest, x, z) addsubl(a, b, dest, subop, sub_overflow, x, z)

#define no_extend(op, a, b, c)	op(a, b, c, 0, z_set)
#define extend(op, a, b, c)		op(a, b, c, extend_flag_, z_or)

#define q() (((decoded_instruction_.full >> 9)&7) ? ((decoded_instruction_.full >> 9)&7) : 8)

								case Operation::ADDb: {
									no_extend(	addb,
												source()->halves.low.halves.low,
												destination()->halves.low.halves.low,
												destination()->halves.low.halves.low);
								} break;

								case Operation::ADDXb: {
									extend(		addb,
												source()->halves.low.halves.low,
												destination()->halves.low.halves.low,
												destination()->halves.low.halves.low);
								} break;

								case Operation::ADDQb: {
									no_extend(	addb,
												q(),
												destination()->halves.low.halves.low,
												destination()->halves.low.halves.low);
								} break;

								case Operation::ADDw: {
									no_extend(	addw,
												source()->halves.low.full,
												destination()->halves.low.full,
												destination()->halves.low.full);
								} break;

								case Operation::ADDXw: {
									extend(		addw,
												source()->halves.low.full,
												destination()->halves.low.full,
												destination()->halves.low.full);
								} break;

								case Operation::ADDQw: {
									no_extend(	addw,
												q(),
												destination()->halves.low.full,
												destination()->halves.low.full);
								} break;

								case Operation::ADDl: {
									no_extend(	addl,
												source()->full,
												destination()->full,
												destination()->full);
								} break;

								case Operation::ADDXl: {
									extend(		addl,
												source()->full,
												destination()->full,
												destination()->full);
								} break;

								case Operation::ADDQl: {
									no_extend(	addl,
												q(),
												destination()->full,
												destination()->full);
								} break;

								case Operation::SUBb: {
									no_extend(	subb,
												source()->halves.low.halves.low,
												destination()->halves.low.halves.low,
												destination()->halves.low.halves.low);
								} break;

								case Operation::SUBXb: {
									extend(		subb,
												source()->halves.low.halves.low,
												destination()->halves.low.halves.low,
												destination()->halves.low.halves.low);
								} break;

								case Operation::SUBQb: {
									no_extend(	subb,
												q(),
												destination()->halves.low.halves.low,
												destination()->halves.low.halves.low);
								} break;

								case Operation::SUBw: {
									no_extend(	subw,
												source()->halves.low.full,
												destination()->halves.low.full,
												destination()->halves.low.full);
								} break;

								case Operation::SUBXw: {
									extend(		subw,
												source()->halves.low.full,
												destination()->halves.low.full,
												destination()->halves.low.full);
								} break;

								case Operation::SUBQw: {
									no_extend(	subw,
												q(),
												destination()->halves.low.full,
												destination()->halves.low.full);
								} break;

								case Operation::SUBl: {
									no_extend(	subl,
												source()->full,
												destination()->full,
												destination()->full);
								} break;

								case Operation::SUBXl: {
									extend(		subl,
												source()->full,
												destination()->full,
												destination()->full);
								} break;

								case Operation::SUBQl: {
									no_extend(	subl,
												q(),
												destination()->full,
												destination()->full);
								} break;

								case Operation::ADDQAl:
									destination()->full += q();
								break;

								case Operation::SUBQAl:
									destination()->full -= q();
								break;

#undef addl
#undef addw
#undef addb
#undef subl
#undef subw
#undef subb
#undef addsubl
#undef addsubw
#undef addsubb
#undef q
#undef z_set
#undef z_or
#undef no_extend
#undef extend
#undef addop
#undef subop


								case Operation::ADDAw:
									destination()->full += u_extend16(source()->halves.low.full);
								break;

								case Operation::ADDAl:
									destination()->full += source()->full;
								break;

								case Operation::SUBAw:
									destination()->full -= u_extend16(source()->halves.low.full);
								break;

								case Operation::SUBAl:
									destination()->full -= source()->full;
								break;


								// BRA: alters the program counter, exclusively via the prefetch queue.
								case Operation::BRA: {
									const int8_t byte_offset = int8_t(prefetch_queue_.halves.high.halves.low);

									// A non-zero offset byte branches by just that amount; otherwise use the word
									// after as an offset. In both cases, treat as signed.
									if(byte_offset) {
										program_counter_.full += uint32_t(byte_offset);
									} else {
										program_counter_.full += u_extend16(prefetch_queue_.halves.low.full);
									}
									program_counter_.full -= 2;
								} break;

								// Two BTSTs: set the zero flag according to the value of the destination masked by
								// the bit named in the source modulo the operation size.
								case Operation::BTSTb:
									zero_result_ = destination()->full & (1 << (source()->full & 7));
								break;

								case Operation::BTSTl:
									zero_result_ = destination()->full & (1 << (source()->full & 31));
								break;

								case Operation::BCLRb:
									zero_result_ = destination()->full & (1 << (source()->full & 7));
									destination()->full &= ~(1 << (source()->full & 7));
								break;

								case Operation::BCLRl:
									zero_result_ = destination()->full & (1 << (source()->full & 31));
									destination()->full &= ~(1 << (source()->full & 31));

									// Clearing in the top word requires an extra four cycles.
									set_next_microcycle_length(HalfCycles(8 + ((source()->full & 31) / 16) * 4));
								break;

								case Operation::BCHGl:
									zero_result_ = destination()->full & (1 << (source()->full & 31));
									destination()->full ^= 1 << (source()->full & 31);
									set_next_microcycle_length(HalfCycles(4 + (((source()->full & 31) / 16) * 4)));
								break;

								case Operation::BCHGb:
									zero_result_ = destination()->halves.low.halves.low & (1 << (source()->full & 7));
									destination()->halves.low.halves.low ^= 1 << (source()->full & 7);
								break;

								case Operation::BSETl:
									zero_result_ = destination()->full & (1 << (source()->full & 31));
									destination()->full |= 1 << (source()->full & 31);
									set_next_microcycle_length(HalfCycles(4 + (((source()->full & 31) / 16) * 4)));
								break;

								case Operation::BSETb:
									zero_result_ = destination()->halves.low.halves.low & (1 << (source()->full & 7));
									destination()->halves.low.halves.low |= 1 << (source()->full & 7);
								break;

								// Bcc: ordinarily evaluates the relevant condition and displacement size and then:
								//	if condition is false, schedules bus operations to get past this instruction;
								//	otherwise applies the offset and schedules bus operations to refill the prefetch queue.
								//
								// Special case: the condition code is 1, which is ordinarily false. In that case this
								// is the trailing step of a BSR.
								case Operation::Bcc: {
									// Grab the 8-bit offset.
									const int8_t byte_offset = int8_t(prefetch_queue_.halves.high.halves.low);

									// Check whether this is secretly BSR.
									const bool is_bsr = ((decoded_instruction_.full >> 8) & 0xf) == 1;

									// Test the conditional, treating 'false' as true.
									const bool should_branch = is_bsr || evaluate_condition(decoded_instruction_.full >> 8);

									// Schedule something appropriate, by rewriting the program for this instruction temporarily.
									if(should_branch) {
										if(byte_offset) {
											program_counter_.full += decltype(program_counter_.full)(byte_offset);
										} else {
											program_counter_.full += u_extend16(prefetch_queue_.halves.low.full);
										}
										program_counter_.full -= 2;
										bus_program = is_bsr ? bsr_bus_steps_ : branch_taken_bus_steps_;
									} else {
										if(byte_offset) {
									 		bus_program = branch_byte_not_taken_bus_steps_;
										} else {
											bus_program = branch_word_not_taken_bus_steps_;
										}
									}
								} break;

								case Operation::DBcc: {
									// Decide what sort of DBcc this is.
									if(!evaluate_condition(decoded_instruction_.full >> 8)) {
										-- source()->halves.low.full;
										const auto target_program_counter = program_counter_.full + u_extend16(prefetch_queue_.halves.low.full) - 2;

										if(source()->halves.low.full == 0xffff) {
											// This DBcc will be ignored as the counter has underflowed.
											// Schedule n np np np and continue. Assumed: the first np
											// is from where the branch would have been if taken?
											bus_program = dbcc_condition_false_no_branch_steps_;
											dbcc_false_address_ = target_program_counter;
										} else {
											// Take the branch. Change PC and schedule n np np.
											bus_program = dbcc_condition_false_branch_steps_;
											program_counter_.full = target_program_counter;
										}
									} else {
										// This DBcc will be ignored as the condition is true;
										// perform nn np np and continue.
										bus_program = dbcc_condition_true_steps_;
									}
								} break;

								case Operation::Scc: {
									destination()->halves.low.halves.low =
										evaluate_condition(decoded_instruction_.full >> 8) ? 0xff : 0x00;
								} break;

								/*
									CLRs: store 0 to the destination, set the zero flag, and clear
									negative, overflow and carry.
								*/
								case Operation::CLRb:
									destination()->halves.low.halves.low = 0;
									negative_flag_ = overflow_flag_ = carry_flag_ = zero_result_ = 0;
								break;

								case Operation::CLRw:
									destination()->halves.low.full = 0;
									negative_flag_ = overflow_flag_ = carry_flag_ = zero_result_ = 0;
								break;

								case Operation::CLRl:
									destination()->full = 0;
									negative_flag_ = overflow_flag_ = carry_flag_ = zero_result_ = 0;
								break;

								/*
									CMP.b, CMP.l and CMP.w: sets the condition flags (other than extend) based on a subtraction
									of the source from the destination; the result of the subtraction is not stored.
								*/
								case Operation::CMPb: {
									const uint8_t source = source()->halves.low.halves.low;
									const uint8_t destination = destination()->halves.low.halves.low;
									const int result = destination - source;

									zero_result_ = result & 0xff;
									carry_flag_ = decltype(carry_flag_)(result & ~0xff);
									negative_flag_ = result & 0x80;
									overflow_flag_ = sub_overflow() & 0x80;
								} break;

								case Operation::CMPw: {
									const uint16_t source = source()->halves.low.full;
									const uint16_t destination = destination()->halves.low.full;
									const int result = destination - source;

									zero_result_ = result & 0xffff;
									carry_flag_ = decltype(carry_flag_)(result & ~0xffff);
									negative_flag_ = result & 0x8000;
									overflow_flag_ = sub_overflow() & 0x8000;
								} break;

								case Operation::CMPAw: {
									const auto source = uint64_t(u_extend16(source()->halves.low.full));
									const uint64_t destination = destination()->full;
									const auto result = destination - source;

									zero_result_ = uint32_t(result);
									carry_flag_ = result >> 32;
									negative_flag_ = result & 0x80000000;
									overflow_flag_ = sub_overflow() & 0x80000000;
								} break;

								case Operation::CMPl: {
									const auto source = uint64_t(source()->full);
									const auto destination = uint64_t(destination()->full);
									const auto result = destination - source;

									zero_result_ = uint32_t(result);
									carry_flag_ = result >> 32;
									negative_flag_ = result & 0x80000000;
									overflow_flag_ = sub_overflow() & 0x80000000;
								} break;

								// JMP: copies EA(0) to the program counter.
								case Operation::JMP:
									program_counter_ = effective_address_[0];
								break;

								// JMP: copies the source bus data to the program counter.
								case Operation::RTS:
									program_counter_ = source_bus_data_[0];
								break;

								/*
									MOVE.b, MOVE.l and MOVE.w: move the least significant byte or word, or the entire long word,
									and set negative, zero, overflow and carry as appropriate.
								*/
								case Operation::MOVEb:
									zero_result_ = destination()->halves.low.halves.low = source()->halves.low.halves.low;
									negative_flag_ = zero_result_ & 0x80;
									overflow_flag_ = carry_flag_ = 0;
								break;

								case Operation::MOVEw:
									zero_result_ = destination()->halves.low.full = source()->halves.low.full;
									negative_flag_ = zero_result_ & 0x8000;
									overflow_flag_ = carry_flag_ = 0;
								break;

								case Operation::MOVEl:
									zero_result_ = destination()->full = source()->full;
									negative_flag_ = zero_result_ & 0x80000000;
									overflow_flag_ = carry_flag_ = 0;
								break;

								/*
									MOVE.q: a single byte is moved from the current instruction, and sign extended.
								*/
								case Operation::MOVEq:
									zero_result_ = destination()->full = prefetch_queue_.halves.high.halves.low;
									negative_flag_ = zero_result_ & 0x80;
									overflow_flag_ = carry_flag_ = 0;
									destination()->full |= negative_flag_ ? 0xffffff00 : 0;
								break;

								/*
									MOVEA.l: move the entire long word;
									MOVEA.w: move the least significant word and sign extend it.
									Neither sets any flags.
								*/
								case Operation::MOVEAw:
									destination()->halves.low.full = source()->halves.low.full;
									destination()->halves.high.full = (destination()->halves.low.full & 0x8000) ? 0xffff : 0;
								break;

								case Operation::MOVEAl:
									destination()->full = source()->full;
								break;

								case Operation::PEA:
									destination_bus_data_[0] = effective_address_[0];
								break;

								/*
									Status word moves and manipulations.
								*/

								case Operation::MOVEtoSR:
									set_status(source()->full);
								break;

								case Operation::MOVEfromSR:
									destination()->halves.low.full = get_status();
								break;

								case Operation::MOVEtoCCR:
									set_ccr(source()->full);
								break;

								case Operation::EXTbtow:
									destination()->halves.low.halves.high =
										(destination()->halves.low.halves.low & 0x80) ? 0xff : 0x00;
									overflow_flag_ = carry_flag_ = 0;
									zero_result_ = destination()->halves.low.full;
									negative_flag_ = zero_result_ & 0x8000;
								break;

								case Operation::EXTwtol:
									destination()->halves.high.full =
										(destination()->halves.low.full & 0x8000) ? 0xffff : 0x0000;
									overflow_flag_ = carry_flag_ = 0;
									zero_result_ = destination()->full;
									negative_flag_ = zero_result_ & 0x80000000;
								break;

#define and_op(a, b) a &= b
#define or_op(a, b) a |= b
#define eor_op(a, b) a ^= b

#define apply(op, func)	{\
	auto status = get_status();	\
	op(status, prefetch_queue_.halves.high.full);	\
	func(status);	\
	program_counter_.full -= 2;	\
}

#define apply_sr(op)	apply(op, set_status)
#define apply_ccr(op)	apply(op, set_ccr)

								case Operation::ANDItoSR:	apply_sr(and_op);	break;
								case Operation::EORItoSR:	apply_sr(eor_op);	break;
								case Operation::ORItoSR:	apply_sr(or_op);	break;

								case Operation::ANDItoCCR:	apply_ccr(and_op);	break;
								case Operation::EORItoCCR:	apply_ccr(eor_op);	break;
								case Operation::ORItoCCR:	apply_ccr(or_op);	break;

#undef apply_ccr
#undef apply_sr
#undef apply
#undef eor_op
#undef or_op
#undef and_op

								/*
									Multiplications.
								*/

								case Operation::MULU: {
									destination()->full = destination()->halves.low.full * source()->halves.low.full;
									carry_flag_ = overflow_flag_ = 0;
									zero_result_ = destination()->full;
									negative_flag_ = zero_result_ & 0x80000000;

									int number_of_ones = source()->halves.low.full;
									convert_to_bit_count_16(number_of_ones);

									// Time taken = 38 cycles + 2 cycles per 1 in the source.
									set_next_microcycle_length(HalfCycles(4 * number_of_ones + 34*2));
								} break;

								case Operation::MULS: {
									destination()->full =
										u_extend16(destination()->halves.low.full) * u_extend16(source()->halves.low.full);
									carry_flag_ = overflow_flag_ = 0;
									zero_result_ = destination()->full;
									negative_flag_ = zero_result_ & 0x80000000;

									// Find the number of 01 or 10 pairs in the 17-bit number
									// formed by the source value with a 0 suffix.
									int number_of_pairs = source()->halves.low.full;
									number_of_pairs = (number_of_pairs ^ (number_of_pairs << 1)) & 0xffff;
									convert_to_bit_count_16(number_of_pairs);

									// Time taken = 38 cycles + 2 cycles per 1 in the source.
									set_next_microcycle_length(HalfCycles(4 * number_of_pairs + 34*2));
								} break;

								/*
									Divisions.
								*/

#define announce_divide_by_zero()									\
	negative_flag_ = overflow_flag_ = 0;							\
	zero_result_ = 1;												\
	active_program_ = nullptr;										\
	active_micro_op_ = short_exception_micro_ops_;					\
	bus_program = &all_bus_steps_[active_micro_op_->bus_program];	\
																	\
	populate_trap_steps(5, get_status());							\
	bus_program->microcycle.length = HalfCycles(20);				\
																	\
	program_counter_.full -= 2;

								case Operation::DIVU: {
									carry_flag_ = 0;

									// An attempt to divide by zero schedules an exception.
									if(!source()->halves.low.full) {
										// Schedule a divide-by-zero exception.
										announce_divide_by_zero();
										break;
									}

									uint32_t dividend = destination()->full;
									uint32_t divisor = source()->halves.low.full;
									const auto quotient = dividend / divisor;

									// If overflow would occur, appropriate flags are set and the result is not written back.
									if(quotient > 65535) {
										overflow_flag_ = zero_result_ = negative_flag_ = 1;
										set_next_microcycle_length(HalfCycles(3*2*2));
										break;
									}

									const uint16_t remainder = uint16_t(dividend % divisor);
									destination()->halves.high.full = remainder;
									destination()->halves.low.full = uint16_t(quotient);

									overflow_flag_ = 0;
									zero_result_ = quotient;
									negative_flag_ = zero_result_ & 0x8000;

									// Calculate cost; this is based on the flowchart in yacht.txt.
									// I could actually calculate the division result here, since this is
									// a classic divide algorithm, but would rather that errors produce
									// incorrect timing only, not incorrect timing plus incorrect results.
									int cycles_expended = 12;	// Covers the nn n to get into the loop.

									divisor <<= 16;
									for(int c = 0; c < 15; ++c) {
										if(dividend & 0x80000000) {
											dividend = (dividend << 1) - divisor;
											cycles_expended += 4;	// Easy; just the fixed nn iteration cost.
										} else {
											dividend <<= 1;

											// Yacht.txt, and indeed a real microprogram, would just subtract here
											// and test the sign of the result, but this is easier to follow:
											if (dividend >= divisor) {
												dividend -= divisor;
												cycles_expended += 6;	// i.e. the original nn plus one further n before going down the MSB=0 route.
											} else {
												cycles_expended += 8;	// The costliest path (since in real life it's a subtraction and then a step
												 						// back from there) — all costs accrue. So the fixed nn loop plus another n,
												 						// plus another one.
											}
										}
									}
									set_next_microcycle_length(HalfCycles(cycles_expended * 2));
								} break;

								case Operation::DIVS: {
									carry_flag_ = 0;

									// An attempt to divide by zero schedules an exception.
									if(!source()->halves.low.full) {
										// Schedule a divide-by-zero exception.
										announce_divide_by_zero()
										break;
									}

									const int32_t signed_dividend = int32_t(destination()->full);
									const int32_t signed_divisor = s_extend16(source()->halves.low.full);
									const auto result_sign =
										( (0 <= signed_dividend) - (signed_dividend < 0) ) *
										( (0 <= signed_divisor) - (signed_divisor < 0) );

									const uint32_t dividend = uint32_t(abs(signed_dividend));
									const uint32_t divisor = uint32_t(abs(signed_divisor));

									int cycles_expended = 12;	// Covers the nn nnn n to get beyond the sign test.
									if(signed_dividend < 0) {
										cycles_expended += 2;	// An additional microycle applies if the dividend is negative.
									}

									// Check for overflow. If it exists, work here is already done.
									const auto quotient = dividend / divisor;
									if(quotient > 32767) {
										overflow_flag_ = 1;
										set_next_microcycle_length(HalfCycles(6*2*2));
										break;
									}

									const uint16_t remainder = uint16_t(signed_dividend % signed_divisor);
									const int signed_quotient = result_sign*int(quotient);
									destination()->halves.high.full = remainder;
									destination()->halves.low.full = uint16_t(signed_quotient);

									zero_result_ = decltype(zero_result_)(signed_quotient);
									negative_flag_ = zero_result_ & 0x8000;
									overflow_flag_ = 0;

									// Algorithm here: there is a fixed cost per unset bit
									// in the first 15 bits of the unsigned quotient.
									auto positive_quotient_bits = ~quotient & 0xfffe;
									convert_to_bit_count_16(positive_quotient_bits);
									cycles_expended += 2 * positive_quotient_bits;

									// There's then no way to terminate the loop that isn't at least ten cycles long;
									// there's also a fixed overhead per bit. The two together add up to the 104 below.
									cycles_expended += 104;

									// This picks up at 'No more bits' in yacht.txt's diagram.
									if(signed_divisor < 0) {
										cycles_expended += 2;
									} else if(signed_dividend < 0) {
										cycles_expended += 4;
									}
									set_next_microcycle_length(HalfCycles(cycles_expended * 2));
								} break;

#undef announce_divide_by_zero

								/*
									MOVEP: move words and long-words a byte at a time.
								*/

								case Operation::MOVEPtoMw:
									// Write pattern is nW+ nw, which should write the low word of the source in big-endian form.
									destination_bus_data_[0].halves.high.full = source()->halves.low.halves.high;
									destination_bus_data_[0].halves.low.full = source()->halves.low.halves.low;
								break;

								case Operation::MOVEPtoMl:
									// Write pattern is nW+ nWr+ nw+ nwr, which should write the source in big-endian form.
									destination_bus_data_[0].halves.high.full = source()->halves.high.halves.high;
									source_bus_data_[0].halves.high.full = source()->halves.high.halves.low;
									destination_bus_data_[0].halves.low.full = source()->halves.low.halves.high;
									source_bus_data_[0].halves.low.full = source()->halves.low.halves.low;
								break;

								case Operation::MOVEPtoRw:
									// Read pattern is nRd+ nrd.
									source()->halves.low.halves.high = destination_bus_data_[0].halves.high.halves.low;
									source()->halves.low.halves.low = destination_bus_data_[0].halves.low.halves.low;
								break;

								case Operation::MOVEPtoRl:
									// Read pattern is nRd+ nR+ nrd+ nr.
									source()->halves.high.halves.high = destination_bus_data_[0].halves.high.halves.low;
									source()->halves.high.halves.low = source_bus_data_[0].halves.high.halves.low;
									source()->halves.low.halves.high = destination_bus_data_[0].halves.low.halves.low;
									source()->halves.low.halves.low = source_bus_data_[0].halves.low.halves.low;
								break;

								/*
									MOVEM: multi-word moves.
								*/

#define setup_movem(words_per_reg, base)								\
	/* Count the number of long words to move.	 */						\
	size_t total_to_move = 0;											\
	auto mask = next_word_;												\
	while(mask) {														\
		total_to_move += mask&1;										\
		mask >>= 1;														\
	}																	\
																		\
	/* Twice that many words plus one will need to be moved */			\
	bus_program = base + (64 - total_to_move*words_per_reg)*2;			\
																		\
	/* Fill in the proper addresses and targets. */						\
	const auto mode = (decoded_instruction_.full >> 3) & 7;				\
	uint32_t start_address;												\
	if(mode <= 4) {														\
		start_address = destination_address().full;						\
	} else {															\
		start_address = effective_address_[1].full;						\
	}																	\
																		\
	auto step = bus_program;											\
	uint32_t *address_storage = precomputed_addresses_;					\
	mask = next_word_;													\
	int offset = 0;

#define inc_action(x, v) x += v
#define dec_action(x, v) x -= v

#define write_address_sequence_long(action, l)														\
	while(mask) {																					\
		if(mask&1) {																				\
			address_storage[0] = start_address;														\
			action(start_address, 2);																\
			address_storage[1] = start_address;														\
			action(start_address, 2);																\
																									\
			step[0].microcycle.address = step[1].microcycle.address = address_storage;				\
			step[2].microcycle.address = step[3].microcycle.address = address_storage + 1;			\
																									\
			const auto target = (offset > 7) ? &address_[offset&7] : &data_[offset];				\
			step[l].microcycle.value = step[l+1].microcycle.value = &target->halves.high;			\
			step[(l^2)].microcycle.value = step[(l^2)+1].microcycle.value = &target->halves.low;	\
																									\
			address_storage += 2;																	\
			step += 4;																				\
		}																							\
		mask >>= 1;																					\
		action(offset, 1);																			\
	}

#define write_address_sequence_word(action)												\
	while(mask) {																		\
		if(mask&1) {																	\
			address_storage[0] = start_address;											\
			action(start_address, 2);													\
																						\
			step[0].microcycle.address = step[1].microcycle.address = address_storage;	\
																						\
			const auto target = (offset > 7) ? &address_[offset&7] : &data_[offset];	\
			step[0].microcycle.value = step[1].microcycle.value = &target->halves.low;	\
																						\
			++ address_storage;															\
			step += 2;																	\
		}																				\
		mask >>= 1;																		\
		action(offset, 1);																\
	}

								case Operation::MOVEMtoRl: {
									setup_movem(2, movem_read_steps_);

									// Everything for move to registers is based on an incrementing
									// address; per M68000PRM:
									//
									// "[If using the postincrement addressing mode then] the incremented address
									// register contains the address of the last operand loaded plus the operand length.
									// If the addressing register is also loaded from memory, the memory value is ignored
									// and the register is written with the postincremented effective address."
									//
									// The latter part is dealt with by MicroOp::Action::MOVEMtoRComplete, which also
									// does any necessary sign extension.
									write_address_sequence_long(inc_action, 0);

									// MOVEM to R always reads one word too many.
									address_storage[0] = start_address;
									step[0].microcycle.address = step[1].microcycle.address = address_storage;
									step[0].microcycle.value = step[1].microcycle.value = &throwaway_value_;
									movem_final_address_ = start_address;
								} break;

								case Operation::MOVEMtoRw: {
									setup_movem(1, movem_read_steps_);
									write_address_sequence_word(inc_action);

									// MOVEM to R always reads one word too many.
									address_storage[0] = start_address;
									step[0].microcycle.address = step[1].microcycle.address = address_storage;
									step[0].microcycle.value = step[1].microcycle.value = &throwaway_value_;
									movem_final_address_ = start_address;
								} break;

								case Operation::MOVEMtoMl: {
									setup_movem(2, movem_write_steps_);

									// MOVEM to M counts downwards and enumerates the registers in reverse order
									// if subject to the predecrementing mode; otherwise it counts upwards and
									// operates exactly as does MOVEM to R.
									//
									// Note also: "The MC68000 and MC68010 write the initial register value
									// (not decremented) [when writing a register that is providing
									// pre-decrementing addressing]."
									//
									// Hence the decrementing register (if any) is updated
									// by MicroOp::Action::MOVEMtoMComplete.
									if(mode == 4) {
										offset = 15;
										start_address -= 2;
										write_address_sequence_long(dec_action, 2);
										movem_final_address_ = start_address + 2;
									} else {
										write_address_sequence_long(inc_action, 0);
									}
								} break;

								case Operation::MOVEMtoMw: {
									setup_movem(1, movem_write_steps_);

									if(mode == 4) {
										offset = 15;
										start_address -= 2;
										write_address_sequence_word(dec_action);
										movem_final_address_ = start_address + 2;
									} else {
										write_address_sequence_word(inc_action);
									}
								} break;

#undef setup_movem
#undef write_address_sequence_long
#undef write_address_sequence_word
#undef inc_action
#undef dec_action

								// TRAP, which is a nicer form of ILLEGAL.
								case Operation::TRAP: {
									// Select the trap steps as next; the initial microcycle should be 4 cycles long.
									bus_program = trap_steps_;
									populate_trap_steps((decoded_instruction_.full & 15) + 32, get_status());
									set_next_microcycle_length(HalfCycles(12));

									// The program counter to push is actually one slot ago.
									program_counter_.full -= 2;
								} break;

								case Operation::TRAPV: {
									if(overflow_flag_) {
										// Select the trap steps as next; the initial microcycle should be skipped.
										bus_program = trap_steps_;
										populate_trap_steps(7, get_status());
										set_next_microcycle_length(HalfCycles(4));

										// Push the address after the TRAPV.
										program_counter_.full -= 4;
									}
								} break;

								case Operation::CHK: {
									const bool is_under = s_extend16(destination()->halves.low.full) < 0;
									const bool is_over = s_extend16(destination()->halves.low.full) > s_extend16(source()->halves.low.full);

									overflow_flag_ = carry_flag_ = 0;
									zero_result_ = destination()->halves.low.full;

									// Test applied for N:
									//
									//	if Dn < 0, set negative flag;
									//	otherwise, if Dn > <ea>, reset negative flag.
									if(is_over) negative_flag_ = 0;
									if(is_under) negative_flag_ = 1;

									// No exception is the default course of action; deviate only if an
									// exception is necessary.
									if(is_under || is_over) {
										bus_program = trap_steps_;
										populate_trap_steps(6, get_status());
										if(is_over) {
											set_next_microcycle_length(HalfCycles(20));
										} else {
											set_next_microcycle_length(HalfCycles(24));
										}

										// The program counter to push is two slots ago as whatever was the correct prefetch
										// to continue without an exception has already happened, just in case.
										program_counter_.full -= 4;
									}
								} break;

								/*
									NEGs: negatives the destination, setting the zero,
									negative, overflow and carry flags appropriate, and extend.

									NB: since the same logic as SUB is used to calculate overflow,
									and SUB calculates `destination - source`, the NEGs deliberately
									label 'source' and 'destination' differently from Motorola.
								*/
								case Operation::NEGb: {
									const int destination = 0;
									const int source = destination()->halves.low.halves.low;
									const auto result = destination - source;
									destination()->halves.low.halves.low = uint8_t(result);

									zero_result_ = result & 0xff;
									extend_flag_ = carry_flag_ = decltype(carry_flag_)(result & ~0xff);
									negative_flag_ = result & 0x80;
									overflow_flag_ = sub_overflow() & 0x80;
								} break;

								case Operation::NEGw: {
									const int destination = 0;
									const int source = destination()->halves.low.full;
									const auto result = destination - source;
									destination()->halves.low.full = uint16_t(result);

									zero_result_ = result & 0xffff;
									extend_flag_ = carry_flag_ = decltype(carry_flag_)(result & ~0xffff);
									negative_flag_ = result & 0x8000;
									overflow_flag_ = sub_overflow() & 0x8000;
								} break;

								case Operation::NEGl: {
									const uint64_t destination = 0;
									const uint64_t source = destination()->full;
									const auto result = destination - source;
									destination()->full = uint32_t(result);

									zero_result_ = uint_fast32_t(result);
									extend_flag_ = carry_flag_ = result >> 32;
									negative_flag_ = result & 0x80000000;
									overflow_flag_ = sub_overflow() & 0x80000000;
								} break;

								/*
									NEGXs: NEG, with extend.
								*/
								case Operation::NEGXb: {
									const int source = destination()->halves.low.halves.low;
									const int destination = 0;
									const auto result = destination - source - (extend_flag_ ? 1 : 0);
									destination()->halves.low.halves.low = uint8_t(result);

									zero_result_ |= result & 0xff;
									extend_flag_ = carry_flag_ = decltype(carry_flag_)(result & ~0xff);
									negative_flag_ = result & 0x80;
									overflow_flag_ = sub_overflow() & 0x80;
								} break;

								case Operation::NEGXw: {
									const int source = destination()->halves.low.full;
									const int destination = 0;
									const auto result = destination - source - (extend_flag_ ? 1 : 0);
									destination()->halves.low.full = uint16_t(result);

									zero_result_ |= result & 0xffff;
									extend_flag_ = carry_flag_ = decltype(carry_flag_)(result & ~0xffff);
									negative_flag_ = result & 0x8000;
									overflow_flag_ = sub_overflow() & 0x8000;
								} break;

								case Operation::NEGXl: {
									const uint64_t source = destination()->full;
									const uint64_t destination = 0;
									const auto result = destination - source - (extend_flag_ ? 1 : 0);
									destination()->full = uint32_t(result);

									zero_result_ |= uint_fast32_t(result);
									extend_flag_ = carry_flag_ = result >> 32;
									negative_flag_ = result & 0x80000000;
									overflow_flag_ = sub_overflow() & 0x80000000;
								} break;

								/*
									The no-op.
								*/
								case Operation::None:
								break;

								/*
									LINK and UNLINK help with stack frames, allowing a certain
									amount of stack space to be allocated or deallocated.
								*/

								case Operation::LINK:
									// Make space for the new long-word value, and set up
									// the proper target address for the stack operations to follow.
									address_[7].full -= 4;
									effective_address_[1].full = address_[7].full;

									// The current value of the address register will be pushed.
									destination_bus_data_[0].full = source()->full;

									// The address register will then contain the bottom of the stack,
									// and the stack pointer will be offset.
									source()->full = address_[7].full;
									address_[7].full += u_extend16(prefetch_queue_.halves.low.full);
								break;

								case Operation::UNLINK:
									address_[7].full = effective_address_[1].full + 2;
									destination()->full = destination_bus_data_[0].full;
								break;

								/*
									TAS: sets zero and negative depending on the current value of the destination,
									and sets the high bit.
								*/

								case Operation::TAS:
									overflow_flag_ = carry_flag_ = 0;
									zero_result_ = destination()->halves.low.halves.low;
									negative_flag_ = destination()->halves.low.halves.low & 0x80;
									destination()->halves.low.halves.low |= 0x80;
								break;

								/*
									Bitwise operators: AND, OR and EOR. All three clear the overflow and carry flags,
									and set zero and negative appropriately.
								*/
#define op_and(x, y)	x &= y
#define op_or(x, y)		x |= y
#define op_eor(x, y)	x ^= y

#define bitwise(source, dest, sign_mask, operator)	\
	operator(dest, source);	\
	overflow_flag_ = carry_flag_ = 0;	\
	zero_result_ = dest;	\
	negative_flag_ = dest & sign_mask;

#define andx(source, dest, sign_mask)	bitwise(source, dest, sign_mask, op_and)
#define eorx(source, dest, sign_mask)	bitwise(source, dest, sign_mask, op_eor)
#define orx(source, dest, sign_mask)	bitwise(source, dest, sign_mask, op_or)

#define op_bwl(name, op)	\
	case Operation::name##b: op(source()->halves.low.halves.low, destination()->halves.low.halves.low, 0x80);	break;	\
	case Operation::name##w: op(source()->halves.low.full, destination()->halves.low.full, 0x8000);				break;	\
	case Operation::name##l: op(source()->full, destination()->full, 0x80000000);								break;

								op_bwl(AND, andx);
								op_bwl(EOR, eorx);
								op_bwl(OR, orx);

#undef op_bwl
#undef orx
#undef eorx
#undef andx
#undef bitwise
#undef op_eor
#undef op_or
#undef op_and

								// NOTs: take the logical inverse, affecting the negative and zero flags.
								case Operation::NOTb:
									destination()->halves.low.halves.low ^= 0xff;
									zero_result_ = destination()->halves.low.halves.low;
									negative_flag_ = zero_result_ & 0x80;
									overflow_flag_ = carry_flag_ = 0;
								break;

								case Operation::NOTw:
									destination()->halves.low.full ^= 0xffff;
									zero_result_ = destination()->halves.low.full;
									negative_flag_ = zero_result_ & 0x8000;
									overflow_flag_ = carry_flag_ = 0;
								break;

								case Operation::NOTl:
									destination()->full ^= 0xffffffff;
									zero_result_ = destination()->full;
									negative_flag_ = zero_result_ & 0x80000000;
									overflow_flag_ = carry_flag_ = 0;
								break;

#define sbcd()																		\
	/* Perform the BCD arithmetic by evaluating the two nibbles separately. */		\
	const int unadjusted_result = destination - source - (extend_flag_ ? 1 : 0);	\
	int result = (destination & 0xf) - (source & 0xf) - (extend_flag_ ? 1 : 0);		\
	if((result & 0x1f) > 0x09) result -= 0x06;										\
	result += (destination & 0xf0) - (source & 0xf0);								\
	extend_flag_ = carry_flag_ = decltype(carry_flag_)((result & 0x1ff) > 0x99);	\
	if(carry_flag_) result -= 0x60;													\
																					\
	/* Set all flags essentially as if this were normal subtraction. */				\
	zero_result_ |= result & 0xff;													\
	negative_flag_ = result & 0x80;													\
	overflow_flag_ = unadjusted_result & ~result & 0x80;							\
																					\
	/* Store the result. */															\
	destination()->halves.low.halves.low = uint8_t(result);

								/*
									SBCD subtracts the lowest byte of the source from that of the destination using
									BCD arithmetic, obeying the extend flag.
								*/
								case Operation::SBCD: {
									const uint8_t source = source()->halves.low.halves.low;
									const uint8_t destination = destination()->halves.low.halves.low;
									sbcd();
								} break;

								/*
									NBCD is like SBCD except that the result is 0 - destination rather than
									destination - source.
								*/
								case Operation::NBCD: {
									const uint8_t source = destination()->halves.low.halves.low;
									const uint8_t destination = 0;
									sbcd();
								} break;

								// EXG and SWAP exchange/swap words or long words.

								case Operation::EXG: {
									const auto temporary = source()->full;
									source()->full = destination()->full;
									destination()->full = temporary;
								} break;

								case Operation::SWAP: {
									const auto temporary = destination()->halves.low.full;
									destination()->halves.low.full = destination()->halves.high.full;
									destination()->halves.high.full = temporary;

									zero_result_ = destination()->full;
									negative_flag_ = temporary & 0x8000;
									overflow_flag_ = carry_flag_ = 0;
								} break;

								/*
									Shifts and rotates.
								*/
#define set_neg_zero(v, m)	\
	zero_result_ = decltype(zero_result_)(v);	\
	negative_flag_ = zero_result_ & decltype(negative_flag_)(m);

#define set_neg_zero_overflow(v, m)	\
	set_neg_zero(v, m);	\
	overflow_flag_ = (decltype(zero_result_)(value) ^ zero_result_) & decltype(overflow_flag_)(m);

#define decode_shift_count()	\
	int shift_count = (decoded_instruction_.full & 32) ? data_[(decoded_instruction_.full >> 9) & 7].full&63 : ( ((decoded_instruction_.full >> 9)&7) ? ((decoded_instruction_.full >> 9)&7) : 8) ;	\
	set_next_microcycle_length(HalfCycles(4 * shift_count));

#define set_flags_b(t) set_flags(destination()->halves.low.halves.low, 0x80, t)
#define set_flags_w(t) set_flags(destination()->halves.low.full, 0x8000, t)
#define set_flags_l(t) set_flags(destination()->full, 0x80000000, t)

#define asl(destination, size)	{\
	decode_shift_count();	\
	const auto value = destination;	\
\
	if(!shift_count) {	\
		carry_flag_ = overflow_flag_ = 0;	\
	} else {	\
		destination = (shift_count < size) ? decltype(destination)(value << shift_count) : 0;	\
		extend_flag_ = carry_flag_ = decltype(carry_flag_)(value) & decltype(carry_flag_)( (1u << (size - 1)) >> (shift_count - 1) );	\
		\
		if(shift_count >= size) overflow_flag_ = value && (value != decltype(value)(-1));	\
		else {	\
			const auto mask = decltype(destination)(0xffffffff << (size - shift_count));	\
			overflow_flag_ = mask & value && ((mask & value) != mask);	\
		}	\
	}	\
\
	set_neg_zero(destination, 1 << (size - 1));	\
}

								case Operation::ASLm: {
									const auto value = destination()->halves.low.full;
									destination()->halves.low.full = uint16_t(value << 1);
									extend_flag_ = carry_flag_ = value & 0x8000;
									set_neg_zero_overflow(destination()->halves.low.full, 0x8000);
								} break;
								case Operation::ASLb: asl(destination()->halves.low.halves.low, 8);	break;
								case Operation::ASLw: asl(destination()->halves.low.full, 16); 		break;
								case Operation::ASLl: asl(destination()->full, 32); 					break;



#define asr(destination, size)	{\
	decode_shift_count();	\
	const auto value = destination;	\
\
	if(!shift_count) {	\
		carry_flag_ = 0;	\
	} else {	\
		destination = (shift_count < size) ?	\
				decltype(destination)(\
					(value >> shift_count) |	\
					((value & decltype(value)(1 << (size - 1)) ? 0xffffffff : 0x000000000) << (size - shift_count))	\
				) :	\
				decltype(destination)(	\
					(value & decltype(value)(1 << (size - 1))) ? 0xffffffff : 0x000000000	\
				);	\
		extend_flag_ = carry_flag_ = decltype(carry_flag_)(value) & decltype(carry_flag_)(1 << (shift_count - 1));	\
	}	\
\
	set_neg_zero_overflow(destination, 1 << (size - 1));	\
}

								case Operation::ASRm: {
									const auto value = destination()->halves.low.full;
									destination()->halves.low.full = (value&0x8000) | (value >> 1);
									extend_flag_ = carry_flag_ = value & 1;
									set_neg_zero_overflow(destination()->halves.low.full, 0x8000);
								} break;
								case Operation::ASRb: asr(destination()->halves.low.halves.low, 8);	break;
								case Operation::ASRw: asr(destination()->halves.low.full, 16); 		break;
								case Operation::ASRl: asr(destination()->full, 32); 					break;


#undef set_neg_zero_overflow
#define set_neg_zero_overflow(v, m)	\
	set_neg_zero(v, m);	\
	overflow_flag_ = 0;

#undef set_flags
#define set_flags(v, m, t)	\
	zero_result_ = v;	\
	negative_flag_ = zero_result_ & (m);	\
	overflow_flag_ = 0;	\
	carry_flag_ = value & (t);

#define lsl(destination, size)	{\
	decode_shift_count();	\
	const auto value = destination;	\
\
	if(!shift_count) {	\
		carry_flag_ = 0;	\
	} else {	\
		destination = (shift_count < size) ? decltype(destination)(value << shift_count) : 0;	\
		extend_flag_ = carry_flag_ = decltype(carry_flag_)(value) & decltype(carry_flag_)( (1u << (size - 1)) >> (shift_count - 1) );	\
	}	\
\
	set_neg_zero_overflow(destination, 1 << (size - 1));	\
}

								case Operation::LSLm: {
									const auto value = destination()->halves.low.full;
									destination()->halves.low.full = uint16_t(value << 1);
									extend_flag_ = carry_flag_ = value & 0x8000;
									set_neg_zero_overflow(destination()->halves.low.full, 0x8000);
								} break;
								case Operation::LSLb: lsl(destination()->halves.low.halves.low, 8);	break;
								case Operation::LSLw: lsl(destination()->halves.low.full, 16); 		break;
								case Operation::LSLl: lsl(destination()->full, 32); 					break;

#define lsr(destination, size)	{\
	decode_shift_count();	\
	const auto value = destination;	\
\
	if(!shift_count) {	\
		carry_flag_ = 0;	\
	} else {	\
		destination = (shift_count < size) ? (value >> shift_count) : 0;	\
		extend_flag_ = carry_flag_ = value & decltype(carry_flag_)(1 << (shift_count - 1));	\
	}	\
\
	set_neg_zero_overflow(destination, 1 << (size - 1));	\
}

								case Operation::LSRm: {
									const auto value = destination()->halves.low.full;
									destination()->halves.low.full = value >> 1;
									extend_flag_ = carry_flag_ = value & 1;
									set_neg_zero_overflow(destination()->halves.low.full, 0x8000);
								} break;
								case Operation::LSRb: lsr(destination()->halves.low.halves.low, 8);	break;
								case Operation::LSRw: lsr(destination()->halves.low.full, 16); 		break;
								case Operation::LSRl: lsr(destination()->full, 32); 					break;

#define rol(destination, size)	{ \
		decode_shift_count();	\
		const auto value = destination;	\
		\
		if(!shift_count) {	\
			carry_flag_ = 0;	\
		} else {	\
			shift_count &= (size - 1);	\
			destination = decltype(destination)(	\
				(value << shift_count) |	\
				(value >> (size - shift_count))	\
			);	\
			carry_flag_ = decltype(carry_flag_)(destination & 1);	\
		}	\
		\
		set_neg_zero_overflow(destination, 1 << (size - 1));	\
	}

								case Operation::ROLm: {
									const auto value = destination()->halves.low.full;
									destination()->halves.low.full = uint16_t((value << 1) | (value >> 15));
									carry_flag_ = destination()->halves.low.full & 1;
									set_neg_zero_overflow(destination()->halves.low.full, 0x8000);
								} break;
								case Operation::ROLb: rol(destination()->halves.low.halves.low, 8);	break;
								case Operation::ROLw: rol(destination()->halves.low.full, 16); 		break;
								case Operation::ROLl: rol(destination()->full, 32); 					break;


#define ror(destination, size)	{ \
		decode_shift_count();	\
		const auto value = destination;	\
		\
		if(!shift_count) {	\
			carry_flag_ = 0;	\
		} else {	\
			shift_count &= (size - 1);	\
			destination = decltype(destination)(\
				(value >> shift_count) |	\
				(value << (size - shift_count))	\
			);\
			carry_flag_ = destination & decltype(carry_flag_)(1 << (size - 1));	\
		}	\
		\
		set_neg_zero_overflow(destination, 1 << (size - 1));	\
	}

								case Operation::RORm: {
									const auto value = destination()->halves.low.full;
									destination()->halves.low.full = uint16_t((value >> 1) | (value << 15));
									carry_flag_ = destination()->halves.low.full & 0x8000;
									set_neg_zero_overflow(destination()->halves.low.full, 0x8000);
								} break;
								case Operation::RORb: ror(destination()->halves.low.halves.low, 8);	break;
								case Operation::RORw: ror(destination()->halves.low.full, 16); 		break;
								case Operation::RORl: ror(destination()->full, 32); 					break;

#define roxl(destination, size)	{ \
	decode_shift_count();	\
\
	shift_count %= (size + 1);	\
	uint64_t compound = uint64_t(destination) | (extend_flag_ ? (1ull << size) : 0);	\
	compound = \
		(compound << shift_count) |	\
		(compound >> (size + 1 - shift_count));	\
	carry_flag_ = extend_flag_ = decltype(carry_flag_)((compound >> size) & 1);	\
	destination = decltype(destination)(compound);	\
	\
	set_neg_zero_overflow(destination, 1 << (size - 1));	\
}


								case Operation::ROXLm: {
									const auto value = destination()->halves.low.full;
									destination()->halves.low.full = uint16_t((value << 1) | (extend_flag_ ? 0x0001 : 0x0000));
									extend_flag_ = value & 0x8000;
									set_flags_w(0x8000);
								} break;
								case Operation::ROXLb: roxl(destination()->halves.low.halves.low, 8);	break;
								case Operation::ROXLw: roxl(destination()->halves.low.full, 16); 		break;
								case Operation::ROXLl: roxl(destination()->full, 32); 					break;

#define roxr(destination, size)	{ \
	decode_shift_count();	\
\
	shift_count %= (size + 1);	\
	uint64_t compound = uint64_t(destination) | (extend_flag_ ? (1ull << size) : 0);	\
	compound = \
		(compound >> shift_count) |	\
		(compound << (size + 1 - shift_count));	\
	carry_flag_ = extend_flag_ = decltype(carry_flag_)((compound >> size) & 1);	\
	destination = decltype(destination)(compound);	\
	\
	set_neg_zero_overflow(destination, 1 << (size - 1));	\
}

								case Operation::ROXRm: {
									const auto value = destination()->halves.low.full;
									destination()->halves.low.full = (value >> 1) | (extend_flag_ ? 0x8000 : 0x0000);
									extend_flag_ = value & 0x0001;
									set_flags_w(0x0001);
								} break;
								case Operation::ROXRb: roxr(destination()->halves.low.halves.low, 8);	break;
								case Operation::ROXRw: roxr(destination()->halves.low.full, 16); 		break;
								case Operation::ROXRl: roxr(destination()->full, 32); 					break;

#undef roxr
#undef roxl
#undef ror
#undef rol
#undef asr
#undef lsr
#undef lsl
#undef asl

#undef set_flags
#undef decode_shift_count
#undef set_flags_b
#undef set_flags_w
#undef set_flags_l
#undef set_neg_zero_overflow
#undef set_net_zero

								/*
									RTE and RTR share an implementation.
								*/
								case Operation::RTE_RTR:
									// If this is RTR, patch out the supervisor half of the status register.
									if(decoded_instruction_.full == 0x4e77) {
										const auto current_status = get_status();
										source_bus_data_[0].halves.low.halves.high =
											uint8_t(current_status >> 8);
									}
									set_status(source_bus_data_[0].full);
								break;

								/*
									TSTs: compare to zero.
								*/

								case Operation::TSTb:
									carry_flag_ = overflow_flag_ = 0;
									zero_result_ = source()->halves.low.halves.low;
									negative_flag_ = zero_result_ & 0x80;
								break;

								case Operation::TSTw:
									carry_flag_ = overflow_flag_ = 0;
									zero_result_ = source()->halves.low.full;
									negative_flag_ = zero_result_ & 0x8000;
								break;

								case Operation::TSTl:
									carry_flag_ = overflow_flag_ = 0;
									zero_result_ = source()->full;
									negative_flag_ = zero_result_ & 0x80000000;
								break;

								case Operation::STOP:
									set_status(prefetch_queue_.halves.low.full);
									execution_state_ = ExecutionState::Stopped;
								break;

								/*
									Development period debugging.
								*/
								default:
									std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl;
								break;
							}
#undef sub_overflow
#undef add_overflow
						break;

						case int_type(MicroOp::Action::MOVEMtoRComplete): {
							// If this was a word-sized move, perform sign extension.
							if(active_program_->operation == Operation::MOVEMtoRw) {
								auto mask = next_word_;
								int offset = 0;
								while(mask) {
									if(mask&1) {
										const auto target = (offset > 7) ? &address_[offset&7] : &data_[offset];
										target->halves.high.full = (target->halves.low.full & 0x8000) ? 0xffff : 0x0000;
									}
									mask >>= 1;
									++offset;
								}
							}

							// If the post-increment mode was used, overwrite the source register.
							const auto mode = (decoded_instruction_.full >> 3) & 7;
							if(mode == 3) {
								const auto reg = decoded_instruction_.full & 7;
								address_[reg] = movem_final_address_;
							}
						} break;

						case int_type(MicroOp::Action::MOVEMtoMComplete): {
							const auto mode = (decoded_instruction_.full >> 3) & 7;
							if(mode == 4) {
								const auto reg = decoded_instruction_.full & 7;
								address_[reg] = movem_final_address_;
							}
						} break;

						case int_type(MicroOp::Action::PrepareJSR): {
							const auto mode = (decoded_instruction_.full >> 3) & 7;
							// Determine the proper resumption address.
							switch(mode) {
								case 2: destination_bus_data_[0].full = program_counter_.full - 2; break;	/* (An) */
								default:
									destination_bus_data_[0].full = program_counter_.full;	/* Everything other than (An) */
								break;
							}
							address_[7].full -= 4;
							effective_address_[1].full = address_[7].full;
						} break;

						case int_type(MicroOp::Action::PrepareBSR):
							destination_bus_data_[0].full = (decoded_instruction_.full & 0xff) ? program_counter_.full - 2 : program_counter_.full;
							address_[7].full -= 4;
							effective_address_[1].full = address_[7].full;
						break;

						case int_type(MicroOp::Action::PrepareRTS):
							effective_address_[0].full = address_[7].full;
							address_[7].full += 4;
						break;

						case int_type(MicroOp::Action::PrepareRTE_RTR):
							precomputed_addresses_[0] = address_[7].full + 2;
							precomputed_addresses_[1] = address_[7].full;
							precomputed_addresses_[2] = address_[7].full + 4;
							address_[7].full += 6;
						break;

						case int_type(MicroOp::Action::PrepareINT):
							// The INT sequence uses the same storage as the TRAP steps, so this'll get
							// the necessary stack work set up.
							populate_trap_steps(0, get_status());

							// Mutate neessary internal state — effective_address_[0] is exposed
							// on the data bus as the accepted interrupt number during the interrupt
							// acknowledge cycle, with all other bits set, including the low bit as
							// a real 68000 uses the lower data strobe to collect the corresponding vector byte.
							//
							// Cf. M68000 8-/16-/32-BIT MICROPROCESSORS USER'S MANUAL 5.1.4.
							accepted_interrupt_level_ = interrupt_level_ = pending_interrupt_level_;
							pending_interrupt_level_ = 0;
							effective_address_[0].full = 0xfffffff1 | uint32_t(accepted_interrupt_level_ << 1);

							// Recede the program counter to where it would have been were there no
							// prefetch; that's where the reading stream should pick up upon RTE.
							program_counter_.full -= 4;
						break;

						case int_type(MicroOp::Action::PrepareINTVector):
							// Let bus error go back to causing exceptions.
							is_starting_interrupt_ = false;

							// Bus error => spurious interrupt.
							if(bus_error_) {
								effective_address_[0].full = 24 << 2;
								break;
							}

							// Valid peripheral address => autovectored interrupt.
							if(is_peripheral_address_) {
								effective_address_[0].full = uint32_t(24 + accepted_interrupt_level_) << 2;
								break;
							}

							// Otherwise, the vector is whatever we were just told it is.
							effective_address_[0].full = uint32_t(source_bus_data_[0].halves.low.halves.low << 2);

//							printf("Interrupt vector: %06x\n", effective_address_[0].full);
						break;

						case int_type(MicroOp::Action::CopyNextWord):
							next_word_ = prefetch_queue_.halves.low.full;
						break;

						// Increments and decrements.
#define op_add(x, y) x += y
#define op_sub(x, y) x -= y
#define Adjust(op, quantity, effect)	\
	case int_type(op) | MicroOp::SourceMask:		effect(source_address().full, quantity);		break;	\
	case int_type(op) | MicroOp::DestinationMask:	effect(destination_address().full, quantity);	break;	\
	case int_type(op) | MicroOp::SourceMask | MicroOp::DestinationMask:	\
		effect(destination_address().full, quantity);	\
		effect(source_address().full, quantity);	\
	break;

						Adjust(MicroOp::Action::Decrement1, 1, op_sub);
						Adjust(MicroOp::Action::Decrement2, 2, op_sub);
						Adjust(MicroOp::Action::Decrement4, 4, op_sub);
						Adjust(MicroOp::Action::Increment1, 1, op_add);
						Adjust(MicroOp::Action::Increment2, 2, op_add);
						Adjust(MicroOp::Action::Increment4, 4, op_add);

#undef Adjust
#undef op_add
#undef op_sub

						case int_type(MicroOp::Action::SignExtendWord):
							if(active_micro_op_->action & MicroOp::SourceMask) {
								source()->halves.high.full =
									(source()->halves.low.full & 0x8000) ? 0xffff : 0x0000;
							}
							if(active_micro_op_->action & MicroOp::DestinationMask) {
								destination()->halves.high.full =
									(destination()->halves.low.full & 0x8000) ? 0xffff : 0x0000;
							}
						break;

						case int_type(MicroOp::Action::SignExtendByte):
							if(active_micro_op_->action & MicroOp::SourceMask) {
								source()->full = (source()->full & 0xff) |
									(source()->full & 0x80) ? 0xffffff : 0x000000;
							}
							if(active_micro_op_->action & MicroOp::DestinationMask) {
								destination()->full = (destination()->full & 0xff) |
									(destination()->full & 0x80) ? 0xffffff : 0x000000;
							}
						break;

						// 16-bit offset addressing modes.

						case int_type(MicroOp::Action::CalcD16PC) | MicroOp::SourceMask:
							// The address the low part of the prefetch queue was read from was two bytes ago, hence
							// the subtraction of 2.
							effective_address_[0] = u_extend16(prefetch_queue_.halves.low.full) + program_counter_.full - 2;
						break;

						case int_type(MicroOp::Action::CalcD16PC) | MicroOp::DestinationMask:
							effective_address_[1] = u_extend16(prefetch_queue_.halves.low.full) + program_counter_.full - 2;
						break;

						case int_type(MicroOp::Action::CalcD16PC) | MicroOp::SourceMask | MicroOp::DestinationMask:
							// Similar logic applies here to above, but the high part of the prefetch queue was four bytes
							// ago rather than merely two.
							effective_address_[0] = u_extend16(prefetch_queue_.halves.high.full) + program_counter_.full - 4;
							effective_address_[1] = u_extend16(prefetch_queue_.halves.low.full) + program_counter_.full - 2;
						break;

						case int_type(MicroOp::Action::CalcD16An) | MicroOp::SourceMask:
							effective_address_[0] = u_extend16(prefetch_queue_.halves.low.full) + source_address().full;
						break;

						case int_type(MicroOp::Action::CalcD16An) | MicroOp::DestinationMask:
							effective_address_[1] = u_extend16(prefetch_queue_.halves.low.full) + destination_address().full;
						break;

						case int_type(MicroOp::Action::CalcD16An) | MicroOp::SourceMask | MicroOp::DestinationMask:
							effective_address_[0] = u_extend16(prefetch_queue_.halves.high.full) + source_address().full;
							effective_address_[1] = u_extend16(prefetch_queue_.halves.low.full) + destination_address().full;
						break;

#define CalculateD8AnXn(data, source, target)	{\
	const auto register_index = (data.full >> 12) & 7;	\
	const RegisterPair32 &displacement = (data.full & 0x8000) ? address_[register_index] : data_[register_index];	\
	target.full = u_extend8(data.halves.low) + source;	\
\
	if(data.full & 0x800) {	\
		target.full += displacement.full;	\
	} else {	\
		target.full += u_extend16(displacement.halves.low.full);	\
	}	\
}
						case int_type(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask: {
							CalculateD8AnXn(prefetch_queue_.halves.low, source_address().full, effective_address_[0]);
						} break;

						case int_type(MicroOp::Action::CalcD8AnXn) | MicroOp::DestinationMask: {
							CalculateD8AnXn(prefetch_queue_.halves.low, destination_address().full, effective_address_[1]);
						} break;

						case int_type(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask | MicroOp::DestinationMask: {
							CalculateD8AnXn(prefetch_queue_.halves.high, source_address().full, effective_address_[0]);
							CalculateD8AnXn(prefetch_queue_.halves.low, destination_address().full, effective_address_[1]);
						} break;

						case int_type(MicroOp::Action::CalcD8PCXn) | MicroOp::SourceMask: {
							CalculateD8AnXn(prefetch_queue_.halves.low, program_counter_.full - 2, effective_address_[0]);
						} break;

						case int_type(MicroOp::Action::CalcD8PCXn) | MicroOp::DestinationMask: {
							CalculateD8AnXn(prefetch_queue_.halves.low, program_counter_.full - 2, effective_address_[1]);
						} break;

						case int_type(MicroOp::Action::CalcD8PCXn) | MicroOp::SourceMask | MicroOp::DestinationMask: {
							CalculateD8AnXn(prefetch_queue_.halves.high, program_counter_.full - 4, effective_address_[0]);
							CalculateD8AnXn(prefetch_queue_.halves.low, program_counter_.full - 2, effective_address_[1]);
						} break;

#undef CalculateD8AnXn

						case int_type(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask:
							effective_address_[0] = u_extend16(prefetch_queue_.halves.low.full);
						break;

						case int_type(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask:
							effective_address_[1] = u_extend16(prefetch_queue_.halves.low.full);
						break;

						case int_type(MicroOp::Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask:
							effective_address_[0] = prefetch_queue_.full;
						break;

						case int_type(MicroOp::Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask:
							effective_address_[1] = prefetch_queue_.full;
						break;

						case int_type(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask:
							source_bus_data_[0] = prefetch_queue_.halves.low.full;
						break;

						case int_type(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::DestinationMask:
							destination_bus_data_[0] = prefetch_queue_.halves.low.full;
						break;

						case int_type(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask:
							source_bus_data_[0] = prefetch_queue_.full;
						break;

						case int_type(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::DestinationMask:
							destination_bus_data_[0] = prefetch_queue_.full;
						break;

						case int_type(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::SourceMask:
							effective_address_[0] = source_address();
						break;

						case int_type(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::DestinationMask:
							effective_address_[1] = destination_address();
						break;

						case int_type(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::SourceMask | MicroOp::DestinationMask:
							effective_address_[0] = source_address();
							effective_address_[1] = destination_address();
						break;
					}

					// If we've got to a micro-op that includes bus steps, break out of this loop.
					if(!active_micro_op_->is_terminal()) {
						active_step_ = bus_program;
						if(!active_step_->is_terminal())
							break;
					}
				}
			}
	}

#undef source
#undef source_address
#undef destination
#undef destination_address

	bus_handler_.flush();
	e_clock_phase_ = (e_clock_phase_ + cycles_run_for) % 10;
	half_cycles_left_to_run_ = remaining_duration - cycles_run_for;
}

template <class T, bool dtack_is_implicit, bool signal_will_perform> ProcessorState Processor<T, dtack_is_implicit, signal_will_perform>::get_state() {
	write_back_stack_pointer();

	State state;
	memcpy(state.data, data_, sizeof(state.data));
	memcpy(state.address, address_, sizeof(state.address));
	state.user_stack_pointer = stack_pointers_[0].full;
	state.supervisor_stack_pointer = stack_pointers_[1].full;
	state.program_counter = program_counter_.full;

	state.status = get_status();

	return state;
}

template <class T, bool dtack_is_implicit, bool signal_will_perform> void Processor<T, dtack_is_implicit, signal_will_perform>::set_state(const ProcessorState &state) {
	memcpy(data_, state.data, sizeof(state.data));
	memcpy(address_, state.address, sizeof(state.address));

	set_status(state.status);

	stack_pointers_[0].full = state.user_stack_pointer;
	stack_pointers_[1].full = state.supervisor_stack_pointer;
	address_[7] = stack_pointers_[is_supervisor_];
}

#undef get_status
#undef set_status
#undef set_ccr
#undef get_ccr
#undef u_extend16
#undef u_extend8
#undef s_extend16
#undef s_extend8
#undef set_next_microcycle_length
#undef convert_to_bit_count_16

