mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Commits at least to decoding MOVEM.
This commit is contained in:
parent
78649a5b54
commit
53f75034fc
@ -72,6 +72,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
active_micro_op_ = active_program_->micro_operations;
|
||||
}
|
||||
|
||||
auto bus_program = active_micro_op_->bus_program;
|
||||
switch(active_micro_op_->action) {
|
||||
default:
|
||||
std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << std::endl;
|
||||
@ -192,12 +193,12 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
program_counter_.full += int16_t(prefetch_queue_.halves.low.full);
|
||||
}
|
||||
program_counter_.full -= 2;
|
||||
active_micro_op_->bus_program = branch_taken_bus_steps_;
|
||||
bus_program = branch_taken_bus_steps_;
|
||||
} else {
|
||||
if(byte_offset) {
|
||||
active_micro_op_->bus_program = branch_byte_not_taken_bus_steps_;
|
||||
bus_program = branch_byte_not_taken_bus_steps_;
|
||||
} else {
|
||||
active_micro_op_->bus_program = branch_word_not_taken_bus_steps_;
|
||||
bus_program = branch_word_not_taken_bus_steps_;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@ -212,17 +213,17 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
// 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?
|
||||
active_micro_op_->bus_program = dbcc_condition_false_no_branch_steps_;
|
||||
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.
|
||||
active_micro_op_->bus_program = dbcc_condition_false_branch_steps_;
|
||||
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.
|
||||
active_micro_op_->bus_program = dbcc_condition_true_steps_;
|
||||
bus_program = dbcc_condition_true_steps_;
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -804,7 +805,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
|
||||
// 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;
|
||||
active_step_ = bus_program;
|
||||
if(!active_step_->is_terminal())
|
||||
break;
|
||||
}
|
||||
|
@ -323,6 +323,9 @@ struct ProcessorStorageConstructor {
|
||||
ASLRLSLRROLRROXLRr, // Maps a destination register to a AS[L/R], LS[L/R], RO[L/R], ROX[L/R]; shift quantities are
|
||||
// decoded at runtime.
|
||||
ASLRLSLRROLRROXLRm, // Maps a destination mode and register to a memory-based AS[L/R], LS[L/R], RO[L/R], ROX[L/R].
|
||||
|
||||
MOVEM, // Maps a mode and register as they were a 'destination' and sets up bus steps with a suitable
|
||||
// hole for the runtime part to install proper MOVEM activity.
|
||||
};
|
||||
|
||||
using Operation = ProcessorStorage::Operation;
|
||||
@ -459,6 +462,11 @@ struct ProcessorStorageConstructor {
|
||||
{0xf1d8, 0xe050, Operation::ROXRw, Decoder::ASLRLSLRROLRROXLRr}, // 4-163 (p267)
|
||||
{0xf1d8, 0xe090, Operation::ROXRl, Decoder::ASLRLSLRROLRROXLRr}, // 4-163 (p267)
|
||||
{0xffc0, 0xe4c0, Operation::ROXRm, Decoder::ASLRLSLRROLRROXLRm}, // 4-163 (p267)
|
||||
|
||||
{0xffc0, 0x48c0, Operation::MOVEMtoMl, Decoder::MOVEM}, // 4-128 (p232)
|
||||
{0xffc0, 0x4880, Operation::MOVEMtoMw, Decoder::MOVEM}, // 4-128 (p232)
|
||||
{0xffc0, 0x4cc0, Operation::MOVEMtoRl, Decoder::MOVEM}, // 4-128 (p232)
|
||||
{0xffc0, 0x4c80, Operation::MOVEMtoRw, Decoder::MOVEM}, // 4-128 (p232)
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
@ -1521,6 +1529,53 @@ struct ProcessorStorageConstructor {
|
||||
op(Action::PerformOperation, seq("np"));
|
||||
} break;
|
||||
|
||||
case Decoder::MOVEM: {
|
||||
// For the sake of commonality, both to R and to M will evaluate their addresses
|
||||
// as if they were destinations.
|
||||
storage_.instructions[instruction].set_destination(storage_, ea_mode, ea_register);
|
||||
|
||||
// Standard prefix: acquire the register selection flags and fetch the next program
|
||||
// word to replace them.
|
||||
op(Action::CopyNextWord, seq("np"));
|
||||
|
||||
// Do whatever is necessary to calculate the proper start address.
|
||||
const int mode = combined_mode(ea_mode, ea_register);
|
||||
const bool is_to_m = (operation == Operation::MOVEMtoMl || operation == Operation::MOVEMtoMw);
|
||||
switch(mode) {
|
||||
default: continue;
|
||||
|
||||
case Ind:
|
||||
case PreDec:
|
||||
case PostInc: {
|
||||
// Deal with the illegal combinations.
|
||||
if(mode == PostInc && is_to_m) continue;
|
||||
if(mode == PreDec && !is_to_m) continue;
|
||||
} break;
|
||||
|
||||
case d16An:
|
||||
case d8AnXn:
|
||||
case d16PC:
|
||||
case d8PCXn:
|
||||
// PC-relative addressing is permitted for moving to registers only.
|
||||
if((mode == d16PC || mode == d8PCXn) && is_to_m) continue;
|
||||
op(calc_action_for_mode(mode) | MicroOp::DestinationMask, seq(pseq("np", mode)));
|
||||
break;
|
||||
|
||||
case XXXl:
|
||||
op(Action::None, seq("np"));
|
||||
case XXXw:
|
||||
op(address_assemble_for_mode(mode) | MicroOp::DestinationMask, seq("np"));
|
||||
break;
|
||||
}
|
||||
|
||||
// Standard suffix: perform the MOVEM, which will mean evaluating the
|
||||
// register selection flags and substituting the necessary reads or writes.
|
||||
op(Action::PerformOperation);
|
||||
|
||||
// A final program fetch will cue up the next instruction.
|
||||
op(Action::None, seq("np"));
|
||||
} break;
|
||||
|
||||
// Decodes the format used by most MOVEs and all MOVEAs.
|
||||
case Decoder::MOVE: {
|
||||
const int destination_mode = (instruction >> 6) & 7;
|
||||
|
@ -77,6 +77,9 @@ class ProcessorStorage {
|
||||
RORb, RORw, RORl, RORm,
|
||||
ROXLb, ROXLw, ROXLl, ROXLm,
|
||||
ROXRb, ROXRw, ROXRl, ROXRm,
|
||||
|
||||
MOVEMtoRl, MOVEMtoRw,
|
||||
MOVEMtoMl, MOVEMtoMw,
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -205,6 +208,9 @@ class ProcessorStorage {
|
||||
|
||||
/// Copies the next two prefetch words into one of the bus_data_.
|
||||
AssembleLongWordDataFromPrefetch,
|
||||
|
||||
/// Copies the low part of the prefetch queue into next_word_.
|
||||
CopyNextWord,
|
||||
};
|
||||
static const int SourceMask = 1 << 30;
|
||||
static const int DestinationMask = 1 << 29;
|
||||
@ -282,7 +288,8 @@ class ProcessorStorage {
|
||||
Program *active_program_ = nullptr;
|
||||
MicroOp *active_micro_op_ = nullptr;
|
||||
BusStep *active_step_ = nullptr;
|
||||
uint16_t decoded_instruction_;
|
||||
uint16_t decoded_instruction_ = 0;
|
||||
uint16_t next_word_ = 0;
|
||||
|
||||
/// Copies address_[7] to the proper stack pointer based on current mode.
|
||||
void write_back_stack_pointer();
|
||||
@ -290,6 +297,14 @@ class ProcessorStorage {
|
||||
/// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated.
|
||||
void set_is_supervisor(bool);
|
||||
|
||||
// Transient storage for MOVEM.
|
||||
uint32_t movem_addresses_[16];
|
||||
RegisterPair32 movem_spare_value_;
|
||||
|
||||
/*!
|
||||
Evaluates the conditional described by @c code and returns @c true or @c false to
|
||||
indicate the result of that evaluation.
|
||||
*/
|
||||
inline bool evaluate_condition(uint8_t code) {
|
||||
switch(code & 0xf) {
|
||||
default:
|
||||
|
Loading…
x
Reference in New Issue
Block a user