mirror of
https://github.com/TomHarte/CLK.git
synced 2024-10-04 01:57:54 +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;
|
active_micro_op_ = active_program_->micro_operations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto bus_program = active_micro_op_->bus_program;
|
||||||
switch(active_micro_op_->action) {
|
switch(active_micro_op_->action) {
|
||||||
default:
|
default:
|
||||||
std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << std::endl;
|
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 += int16_t(prefetch_queue_.halves.low.full);
|
||||||
}
|
}
|
||||||
program_counter_.full -= 2;
|
program_counter_.full -= 2;
|
||||||
active_micro_op_->bus_program = branch_taken_bus_steps_;
|
bus_program = branch_taken_bus_steps_;
|
||||||
} else {
|
} else {
|
||||||
if(byte_offset) {
|
if(byte_offset) {
|
||||||
active_micro_op_->bus_program = branch_byte_not_taken_bus_steps_;
|
bus_program = branch_byte_not_taken_bus_steps_;
|
||||||
} else {
|
} else {
|
||||||
active_micro_op_->bus_program = branch_word_not_taken_bus_steps_;
|
bus_program = branch_word_not_taken_bus_steps_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} 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.
|
// This DBcc will be ignored as the counter has underflowed.
|
||||||
// Schedule n np np np and continue. Assumed: the first np
|
// Schedule n np np np and continue. Assumed: the first np
|
||||||
// is from where the branch would have been if taken?
|
// 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;
|
dbcc_false_address_ = target_program_counter;
|
||||||
} else {
|
} else {
|
||||||
// Take the branch. Change PC and schedule n np np.
|
// 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;
|
program_counter_.full = target_program_counter;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This DBcc will be ignored as the condition is true;
|
// This DBcc will be ignored as the condition is true;
|
||||||
// perform nn np np and continue.
|
// perform nn np np and continue.
|
||||||
active_micro_op_->bus_program = dbcc_condition_true_steps_;
|
bus_program = dbcc_condition_true_steps_;
|
||||||
}
|
}
|
||||||
} break;
|
} 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 we've got to a micro-op that includes bus steps, break out of this loop.
|
||||||
if(!active_micro_op_->is_terminal()) {
|
if(!active_micro_op_->is_terminal()) {
|
||||||
active_step_ = active_micro_op_->bus_program;
|
active_step_ = bus_program;
|
||||||
if(!active_step_->is_terminal())
|
if(!active_step_->is_terminal())
|
||||||
break;
|
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
|
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.
|
// 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].
|
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;
|
using Operation = ProcessorStorage::Operation;
|
||||||
@ -459,6 +462,11 @@ struct ProcessorStorageConstructor {
|
|||||||
{0xf1d8, 0xe050, Operation::ROXRw, Decoder::ASLRLSLRROLRROXLRr}, // 4-163 (p267)
|
{0xf1d8, 0xe050, Operation::ROXRw, Decoder::ASLRLSLRROLRROXLRr}, // 4-163 (p267)
|
||||||
{0xf1d8, 0xe090, Operation::ROXRl, Decoder::ASLRLSLRROLRROXLRr}, // 4-163 (p267)
|
{0xf1d8, 0xe090, Operation::ROXRl, Decoder::ASLRLSLRROLRROXLRr}, // 4-163 (p267)
|
||||||
{0xffc0, 0xe4c0, Operation::ROXRm, Decoder::ASLRLSLRROLRROXLRm}, // 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
|
#ifndef NDEBUG
|
||||||
@ -1521,6 +1529,53 @@ struct ProcessorStorageConstructor {
|
|||||||
op(Action::PerformOperation, seq("np"));
|
op(Action::PerformOperation, seq("np"));
|
||||||
} break;
|
} 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.
|
// Decodes the format used by most MOVEs and all MOVEAs.
|
||||||
case Decoder::MOVE: {
|
case Decoder::MOVE: {
|
||||||
const int destination_mode = (instruction >> 6) & 7;
|
const int destination_mode = (instruction >> 6) & 7;
|
||||||
|
@ -77,6 +77,9 @@ class ProcessorStorage {
|
|||||||
RORb, RORw, RORl, RORm,
|
RORb, RORw, RORl, RORm,
|
||||||
ROXLb, ROXLw, ROXLl, ROXLm,
|
ROXLb, ROXLw, ROXLl, ROXLm,
|
||||||
ROXRb, ROXRw, ROXRl, ROXRm,
|
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_.
|
/// Copies the next two prefetch words into one of the bus_data_.
|
||||||
AssembleLongWordDataFromPrefetch,
|
AssembleLongWordDataFromPrefetch,
|
||||||
|
|
||||||
|
/// Copies the low part of the prefetch queue into next_word_.
|
||||||
|
CopyNextWord,
|
||||||
};
|
};
|
||||||
static const int SourceMask = 1 << 30;
|
static const int SourceMask = 1 << 30;
|
||||||
static const int DestinationMask = 1 << 29;
|
static const int DestinationMask = 1 << 29;
|
||||||
@ -282,7 +288,8 @@ class ProcessorStorage {
|
|||||||
Program *active_program_ = nullptr;
|
Program *active_program_ = nullptr;
|
||||||
MicroOp *active_micro_op_ = nullptr;
|
MicroOp *active_micro_op_ = nullptr;
|
||||||
BusStep *active_step_ = 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.
|
/// Copies address_[7] to the proper stack pointer based on current mode.
|
||||||
void write_back_stack_pointer();
|
void write_back_stack_pointer();
|
||||||
@ -290,6 +297,14 @@ class ProcessorStorage {
|
|||||||
/// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated.
|
/// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated.
|
||||||
void set_is_supervisor(bool);
|
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) {
|
inline bool evaluate_condition(uint8_t code) {
|
||||||
switch(code & 0xf) {
|
switch(code & 0xf) {
|
||||||
default:
|
default:
|
||||||
|
Loading…
Reference in New Issue
Block a user