1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +00:00

Starts MOVE tests; in pursuit of which talks the 68000 into obeying run lengths.

This commit is contained in:
Thomas Harte 2019-03-21 22:30:41 -04:00
parent f679145bd1
commit fdc598f2e1
4 changed files with 360 additions and 246 deletions

View File

@ -120,4 +120,18 @@ class RAM68000: public CPU::MC68000::BusHandler {
_machine->run_for(HalfCycles(400));
}
- (void)testMOVE {
_machine->set_program({
0x303c, 0xfb2e // MOVE #fb2e, D0
});
_machine->run_for(Cycles(38));
auto state = _machine->get_processor_state();
XCTAssert(state.data[0] == 0);
_machine->run_for(Cycles(8));
state = _machine->get_processor_state();
XCTAssert(state.data[0] == 0xfb2e);
}
@end

View File

@ -7,8 +7,235 @@
//
template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>::run_for(HalfCycles duration) {
// TODO: obey the 'cycles' count.
while(true) {
HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
while(remaining_duration > HalfCycles(0)) {
/*
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.
// TODO: unless an interrupt is pending, or the trap flag is set.
const uint16_t next_instruction = prefetch_queue_.halves.high.full;
if(!instructions[next_instruction].micro_operations) {
// TODO: once all instructions are implemnted, this should be an instruction error.
std::cerr << "68000 Abilities exhausted; can't manage instruction " << std::hex << next_instruction << std::endl;
return;
}
active_program_ = &instructions[next_instruction];
active_micro_op_ = active_program_->micro_operations;
}
switch(active_micro_op_->action) {
default:
std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << std::endl;
break;
case int(MicroOp::Action::None): break;
case int(MicroOp::Action::PerformOperation):
switch(active_program_->operation) {
case Operation::ABCD: {
// Pull out the two halves, for simplicity.
const uint8_t source = active_program_->source->halves.low.halves.low;
const uint8_t destination = active_program_->destination->halves.low.halves.low;
// Perform the BCD add by evaluating the two nibbles separately.
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_flag_ |= result & 0xff;
extend_flag_ = carry_flag_ = result & ~0xff;
negative_flag_ = result & 0x80;
overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80;
// Store the result.
active_program_->destination->halves.low.halves.low = uint8_t(result);
} break;
case Operation::SBCD: {
// Pull out the two halves, for simplicity.
const uint8_t source = active_program_->source->halves.low.halves.low;
const uint8_t destination = active_program_->destination->halves.low.halves.low;
// Perform the BCD add by evaluating the two nibbles separately.
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 subtraction.
zero_flag_ |= result & 0xff;
extend_flag_ = carry_flag_ = result & ~0xff;
negative_flag_ = result & 0x80;
overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80;
// Store the result.
active_program_->destination->halves.low.halves.low = uint8_t(result);
} break;
case Operation::MOVEb:
zero_flag_ = active_program_->destination->halves.low.halves.low = active_program_->source->halves.low.halves.low;
negative_flag_ = zero_flag_ & 0x80;
overflow_flag_ = carry_flag_ = 0;
break;
case Operation::MOVEw:
zero_flag_ = active_program_->destination->halves.low.full = active_program_->source->halves.low.full;
negative_flag_ = zero_flag_ & 0x8000;
overflow_flag_ = carry_flag_ = 0;
break;
case Operation::MOVEl:
zero_flag_ = active_program_->destination->full = active_program_->source->full;
negative_flag_ = zero_flag_ & 0x80000000;
overflow_flag_ = carry_flag_ = 0;
break;
default:
std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl;
break;
}
break;
case int(MicroOp::Action::SetMoveFlagsb):
zero_flag_ = active_program_->source->halves.low.halves.low;
negative_flag_ = zero_flag_ & 0x80;
overflow_flag_ = carry_flag_ = 0;
break;
case int(MicroOp::Action::SetMoveFlagsw):
zero_flag_ = active_program_->source->halves.low.full;
negative_flag_ = zero_flag_ & 0x8000;
overflow_flag_ = carry_flag_ = 0;
break;
case int(MicroOp::Action::SetMoveFlagsl):
zero_flag_ = active_program_->source->full;
negative_flag_ = zero_flag_ & 0x80000000;
overflow_flag_ = carry_flag_ = 0;
break;
case int(MicroOp::Action::Decrement1):
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full -= 1;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full -= 1;
break;
case int(MicroOp::Action::Decrement2):
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full -= 2;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full -= 2;
break;
case int(MicroOp::Action::Decrement4):
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full -= 4;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full -= 4;
break;
case int(MicroOp::Action::Increment1):
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full += 1;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full += 1;
break;
case int(MicroOp::Action::Increment2):
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full += 2;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full += 2;
break;
case int(MicroOp::Action::Increment4):
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full += 4;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full += 4;
break;
case int(MicroOp::Action::SignExtendWord):
if(active_micro_op_->action & MicroOp::SourceMask) {
active_program_->source->halves.high.full =
(active_program_->source->halves.low.full & 0x8000) ? 0xffff : 0x0000;
}
if(active_micro_op_->action & MicroOp::DestinationMask) {
active_program_->destination->halves.high.full =
(active_program_->destination->halves.low.full & 0x8000) ? 0xffff : 0x0000;
}
break;
case int(MicroOp::Action::SignExtendByte):
if(active_micro_op_->action & MicroOp::SourceMask) {
active_program_->source->full = (active_program_->source->full & 0xff) |
(active_program_->source->full & 0x80) ? 0xffffff : 0x000000;
}
if(active_micro_op_->action & MicroOp::DestinationMask) {
active_program_->destination->full = (active_program_->destination->full & 0xff) |
(active_program_->destination->full & 0x80) ? 0xffffff : 0x000000;
}
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::SourceMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.high.full) + active_program_->source->full;
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::DestinationMask:
effective_address_[1] = int16_t(prefetch_queue_.halves.high.full) + active_program_->destination->full;
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::SourceMask | MicroOp::DestinationMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.high.full) + active_program_->source->full;
effective_address_[1] = int16_t(prefetch_queue_.halves.low.full) + active_program_->destination->full;
break;
// TODO: permit as below for DestinationMask and SourceMask|DestinationMask; would prefer to test first.
#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 = int8_t(data.halves.low) + source->full; \
\
if(data.full & 0x800) { \
effective_address_[0] += displacement.halves.low.full; \
} else { \
effective_address_[0] += displacement.full; \
} \
}
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask: {
CalculateD8AnXn(prefetch_queue_.halves.high, active_program_->source, effective_address_[0]);
} break;
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::DestinationMask: {
CalculateD8AnXn(prefetch_queue_.halves.high, active_program_->destination, effective_address_[1]);
} break;
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask | MicroOp::DestinationMask: {
CalculateD8AnXn(prefetch_queue_.halves.high, active_program_->source, effective_address_[0]);
CalculateD8AnXn(prefetch_queue_.halves.low, active_program_->destination, effective_address_[1]);
} break;
#undef CalculateD8AnXn
case int(MicroOp::Action::AssembleWordFromPrefetch) | MicroOp::SourceMask:
bus_data_[0] = prefetch_queue_.full;
break;
case int(MicroOp::Action::AssembleWordFromPrefetch) | MicroOp::DestinationMask:
bus_data_[1] = prefetch_queue_.full;
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_ = active_micro_op_->bus_program;
break;
}
}
}
/*
PERFORM THE CURRENT BUS STEP'S MICROCYCLE.
@ -26,240 +253,36 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
// TODO: check for bus error.
// Perform the microcycle.
bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
remaining_duration -=
active_step_->microcycle.length +
bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
/*
PERFORM THE BUS STEP'S ACTION.
*/
if(!active_step_->is_terminal()) {
switch(active_step_->action) {
default:
std::cerr << "Unimplemented 68000 bus step action: " << int(active_step_->action) << std::endl;
return;
break;
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::None: break;
case BusStep::Action::IncrementEffectiveAddress0: effective_address_[0] += 2; break;
case BusStep::Action::IncrementEffectiveAddress1: effective_address_[1] += 2; break;
case BusStep::Action::IncrementProgramCounter: program_counter_.full += 2; break;
case BusStep::Action::IncrementEffectiveAddress0: effective_address_[0] += 2; break;
case BusStep::Action::IncrementEffectiveAddress1: effective_address_[1] += 2; break;
case BusStep::Action::IncrementProgramCounter: program_counter_.full += 2; break;
case BusStep::Action::AdvancePrefetch:
prefetch_queue_.halves.high = prefetch_queue_.halves.low;
break;
}
// Move to the next bus step.
++ active_step_;
// Skip the micro-op renavigation below.
continue;
case BusStep::Action::AdvancePrefetch:
prefetch_queue_.halves.high = prefetch_queue_.halves.low;
break;
}
/*
FIND THE NEXT MICRO-OP.
*/
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.
// TODO: unless an interrupt is pending, or the trap flag is set.
const uint16_t next_instruction = prefetch_queue_.halves.high;
if(!instructions[next_instruction].micro_operations) {
// TODO: once all instructions are implemnted, this should be an instruction error.
std::cerr << "68000 Abilities exhausted; can't manage instruction " << std::hex << next_instruction << std::endl;
return;
}
active_program_ = &instructions[next_instruction];
active_micro_op_ = active_program_->micro_operations;
}
switch(active_micro_op_->action) {
default:
std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << std::endl;
break;
case MicroOp::Action::None: break;
case MicroOp::Action::PerformOperation:
switch(active_program_->operation) {
case Operation::ABCD: {
// Pull out the two halves, for simplicity.
const uint8_t source = active_program_->source->halves.low.halves.low;
const uint8_t destination = active_program_->destination->halves.low.halves.low;
// Perform the BCD add by evaluating the two nibbles separately.
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_flag_ |= result & 0xff;
extend_flag_ = carry_flag_ = result & ~0xff;
negative_flag_ = result & 0x80;
overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80;
// Store the result.
active_program_->destination->halves.low.halves.low = uint8_t(result);
} break;
case Operation::SBCD: {
// Pull out the two halves, for simplicity.
const uint8_t source = active_program_->source->halves.low.halves.low;
const uint8_t destination = active_program_->destination->halves.low.halves.low;
// Perform the BCD add by evaluating the two nibbles separately.
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 subtraction.
zero_flag_ |= result & 0xff;
extend_flag_ = carry_flag_ = result & ~0xff;
negative_flag_ = result & 0x80;
overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80;
// Store the result.
active_program_->destination->halves.low.halves.low = uint8_t(result);
} break;
case Operation::MOVEb:
zero_flag_ = active_program_->destination->halves.low.halves.low = active_program_->source->halves.low.halves.low;
negative_flag_ = zero_flag_ & 0x80;
break;
case Operation::MOVEw:
zero_flag_ = active_program_->destination->halves.low.full = active_program_->source->halves.low.full;
negative_flag_ = zero_flag_ & 0x8000;
break;
case Operation::MOVEl:
zero_flag_ = active_program_->destination->full = active_program_->source->full;
negative_flag_ = zero_flag_ & 0x80000000;
break;
default:
std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl;
break;
}
break;
case MicroOp::Action::Decrement1:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full -= 1;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full -= 1;
break;
case MicroOp::Action::Decrement2:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full -= 2;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full -= 2;
break;
case MicroOp::Action::Decrement4:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full -= 4;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full -= 4;
break;
case MicroOp::Action::Increment1:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full += 1;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full += 1;
break;
case MicroOp::Action::Increment2:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full += 2;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full += 2;
break;
case MicroOp::Action::Increment4:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full += 4;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full += 4;
break;
case MicroOp::Action::SignExtendWord:
if(active_micro_op_->action & MicroOp::SourceMask) {
active_program_->source->halves.high.full =
(active_program_->source->halves.low.full & 0x8000) ? 0xffff : 0x0000;
}
if(active_micro_op_->action & MicroOp::DestinationMask) {
active_program_->destination->halves.high.full =
(active_program_->destination->halves.low.full & 0x8000) ? 0xffff : 0x0000;
}
break;
case MicroOp::Action::SignExtendByte:
if(active_micro_op_->action & MicroOp::SourceMask) {
active_program_->source->full = (active_program_->source->full & 0xff) |
(active_program_->source->full & 0x80) ? 0xffffff : 0x000000;
}
if(active_micro_op_->action & MicroOp::DestinationMask) {
active_program_->destination->full = (active_program_->destination->full & 0xff) |
(active_program_->destination->full & 0x80) ? 0xffffff : 0x000000;
}
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::SourceMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.high) + active_program_->source->full;
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::DestinationMask:
effective_address_[1] = int16_t(prefetch_queue_.halves.high) + active_program_->destination->full;
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::SourceMask | MicroOp::DestinationMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.high) + active_program_->source->full;
effective_address_[1] = int16_t(prefetch_queue_.halves.low) + active_program_->destination->full;
break;
// TODO: permit as below for DestinationMask and SourceMask|DestinationMask; would prefer to test first.
#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 = int8_t(data.halves.low) + source->full; \
\
if(data.full & 0x800) { \
effective_address_[0] += displacement.halves.low; \
} else { \
effective_address_[0] += displacement.full; \
} \
}
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask: {
CalculateD8AnXn(prefetch_queue_.halves.high, active_program_->source, effective_address_[0]);
} break;
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::DestinationMask: {
CalculateD8AnXn(prefetch_queue_.halves.high, active_program_->destination, effective_address_[1]);
} break;
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask | MicroOp::DestinationMask: {
CalculateD8AnXn(prefetch_queue_.halves.high, active_program_->source, effective_address_[0]);
CalculateD8AnXn(prefetch_queue_.halves.low, active_program_->destination, effective_address_[1]);
} break;
#undef CalculateD8AnXn
case int(MicroOp::Action::AssembleWordFromPrefetch) | MicroOp::SourceMask:
bus_data_[0] = prefetch_queue_.full;
break;
case int(MicroOp::Action::AssembleWordFromPrefetch) | MicroOp::DestinationMask:
bus_data_[1] = prefetch_queue_.full;
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_ = active_micro_op_->bus_program;
break;
}
}
// Move to the next bus step.
++ active_step_;
}
half_cycles_left_to_run_ = remaining_duration;
}
template <class T, bool dtack_is_implicit> ProcessorState Processor<T, dtack_is_implicit>::get_state() {

View File

@ -327,6 +327,11 @@ struct ProcessorStorageConstructor {
const bool is_byte_access = mapping.operation == Operation::MOVEb;
const bool is_long_word_access = mapping.operation == Operation::MOVEl;
// There are no byte moves to address registers.
if(is_byte_access && destination_mode == 1) {
continue;
}
// Construct a single word to describe the addressing mode:
//
// 0xssdd, where ss or dd =
@ -371,21 +376,26 @@ struct ProcessorStorageConstructor {
case 0x0001: // MOVEA Dn, An
case 0x0101: // MOVEA An, An
op(Action::PerformOperation, seq("np"));
op(
int(is_byte_access ? Action::SignExtendByte : Action::SignExtendWord) | MicroOp::DestinationMask
);
op(int(Action::SignExtendWord) | MicroOp::DestinationMask);
break;
case 0x0002: // MOVE Dn, (An)
case 0x0102: // MOVE An, (An)
case 0x0003: // MOVE Dn, (An)+
case 0x0103: // MOVE An, (An)+
// nw np
op(is_byte_access ? Action::SetMoveFlagsb : Action::SetMoveFlagsw, seq("nw np", { &storage_.address_[destination_register].full }, !is_byte_access));
if(destination_mode == 0x3) {
op(int(is_byte_access ? Action::Increment1 : Action::Increment2) | MicroOp::DestinationMask);
} else {
op();
}
continue;
case 0x0004: // MOVE Dn, -(An)
case 0x0104: // MOVE An, -(An)
// np nw
op( int(is_byte_access ? Action::Decrement1 : Action::Decrement2) | MicroOp::DestinationMask,
seq("np nw", { &storage_.address_[destination_register].full }, !is_byte_access));
op(is_byte_access ? Action::SetMoveFlagsb : Action::SetMoveFlagsw);
continue;
case 0x0005: // MOVE Dn, (d16, An)
@ -415,11 +425,8 @@ struct ProcessorStorageConstructor {
case 0x0200: // MOVE (An), Dn
case 0x0300: // MOVE (An)+, Dn
op(Action::None, seq("nr np", { &storage_.address_[source_register].full }, !is_byte_access));
if(source_mode == 0x3 || destination_mode == 0x3) {
op(int(is_byte_access ? Action::Increment1 : Action::Increment2)
| (source_mode == 3 ? MicroOp::SourceMask : 0)
| (destination_mode == 3 ? MicroOp::DestinationMask : 0)
);
if(source_mode == 0x3) {
op(int(is_byte_access ? Action::Increment1 : Action::Increment2) | MicroOp::SourceMask);
}
op(Action::PerformOperation);
break;
@ -492,23 +499,59 @@ struct ProcessorStorageConstructor {
continue;
//
// Source = (d16, An)
// Source = (d16, An) or (d8, An, Xn)
//
#define action_calc() int(source_mode == 0x05 ? Action::CalcD16An : Action::CalcD8AnXn)
#define pseq(x) (source_mode == 0x06 ? "n" x : x)
case 0x0500: // MOVE (d16, An), Dn
op(int(Action::CalcD16An) | MicroOp::SourceMask, seq("np nr np", { &storage_.effective_address_[0] }, !is_byte_access));
op(Action::PerformOperation);
break;
//
// Source = (d8, An, Xn)
//
case 0x0600: // MOVE (d8, An, Xn), Dn
op(int(Action::CalcD8AnXn) | MicroOp::SourceMask, seq("n np nr np", { &storage_.effective_address_[0] }, !is_byte_access));
op(action_calc() | MicroOp::SourceMask, seq(pseq("np nr np"), { &storage_.effective_address_[0] }, !is_byte_access));
op(Action::PerformOperation);
break;
case 0x0502: // MOVE (d16, An), (An)
case 0x0503: // MOVE (d16, An), (An)+
case 0x0602: // MOVE (d8, An, Xn), (An)
case 0x0603: // MOVE (d8, An, Xn), (An)+
// np nr nw np
// n np nr nw np
continue;
case 0x0504: // MOVE (d16, An), -(An)
case 0x0604: // MOVE (d8, An, Xn), -(An)
// np nr np nw
// n np nr np nw
continue;
case 0x0505: // MOVE (d16, An), (d16, An)
case 0x0605: // MOVE (d8, An, Xn), (d16, An)
// np nr np nw np
// n np nr np nw np
continue;
case 0x0506: // MOVE (d16, An), (d8, An, Xn)
case 0x0606: // MOVE (d8, An, Xn), (d8, An, Xn)
// np nr n np nw np
// n np nr n np nw np
continue;
case 0x0510: // MOVE (d16, An), (xxx).W
case 0x0610: // MOVE (d8, An, Xn), (xxx).W
// np nr np nw np
// n np nr np nw np
continue;
case 0x0511: // MOVE (d16, An), (xxx).L
case 0x0611: // MOVE (d8, An, Xn), (xxx).L
// np nr np nw np np
// n np nr np nw np np
continue;
#undef action_calc
#undef prefix
//
// Source = (xxx).W
//
@ -517,6 +560,31 @@ struct ProcessorStorageConstructor {
// np nr np
continue;
case 0x1002: // MOVE (xxx).W, (An)
case 0x1003: // MOVE (xxx).W, (An)+
// np nr nw np
continue;
case 0x1004: // MOVE (xxx).W, -(An)
// np nr np nw
continue;
case 0x1005: // MOVE (xxx).W, (d16, An)
// np nr np nw np
continue;
case 0x1006: // MOVE (xxx).W, (d8, An, Xn)
// np nr n np nw np
continue;
case 0x1010: // MOVE (xxx).W, (xxx).W
// np nr np nw np
continue;
case 0x1011: // MOVE (xxx).W, (xxx).L
// np nr np nw np np
continue;
//
// Source = (xxx).L
//

View File

@ -37,6 +37,8 @@ class ProcessorStorage {
uint32_t effective_address_[2];
RegisterPair32 bus_data_[2];
HalfCycles half_cycles_left_to_run_;
enum class Operation {
ABCD, SBCD,
ADD, AND, EOR, OR, SUB,
@ -98,8 +100,15 @@ class ProcessorStorage {
struct MicroOp {
enum class Action: int {
None,
/// Does whatever this instruction says is the main operation.
PerformOperation,
/// Sets the flags as if a MOVE operation had occurred, by inspecting *source.
SetMoveFlagsb,
SetMoveFlagsw,
SetMoveFlagsl,
/*
All of the below will honour the source and destination masks
in deciding where to apply their actions.