mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Starts MOVE tests; in pursuit of which talks the 68000 into obeying run lengths.
This commit is contained in:
parent
f679145bd1
commit
fdc598f2e1
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user