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

Commits at least to decoding MOVEM.

This commit is contained in:
Thomas Harte 2019-04-14 14:09:28 -04:00
parent 78649a5b54
commit 53f75034fc
3 changed files with 79 additions and 8 deletions

View File

@ -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;
}

View File

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

View File

@ -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: