1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-26 09:29:45 +00:00

Implements LEA.

This commit is contained in:
Thomas Harte 2019-03-26 22:07:28 -04:00
parent 6f0eb5eccd
commit 42634b500c
3 changed files with 81 additions and 32 deletions

View File

@ -359,16 +359,15 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
effective_address_[1] = int16_t(prefetch_queue_.halves.low.full) + active_program_->destination->full; effective_address_[1] = int16_t(prefetch_queue_.halves.low.full) + active_program_->destination->full;
break; break;
// TODO: permit as below for DestinationMask and SourceMask|DestinationMask; would prefer to test first.
#define CalculateD8AnXn(data, source, target) {\ #define CalculateD8AnXn(data, source, target) {\
const auto register_index = (data.full >> 12) & 7; \ const auto register_index = (data.full >> 12) & 7; \
const RegisterPair32 &displacement = (data.full & 0x8000) ? address_[register_index] : data_[register_index]; \ const RegisterPair32 &displacement = (data.full & 0x8000) ? address_[register_index] : data_[register_index]; \
target = int8_t(data.halves.low) + source->full; \ target.full = int8_t(data.halves.low) + source->full; \
\ \
if(data.full & 0x800) { \ if(data.full & 0x800) { \
effective_address_[0] += displacement.halves.low.full; \ target.full += displacement.halves.low.full; \
} else { \ } else { \
effective_address_[0] += displacement.full; \ target.full += displacement.full; \
} \ } \
} }
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask: { case int(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask: {
@ -462,9 +461,9 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
case BusStep::Action::None: break; case BusStep::Action::None: break;
case BusStep::Action::IncrementEffectiveAddress0: effective_address_[0] += 2; break; case BusStep::Action::IncrementEffectiveAddress0: effective_address_[0].full += 2; break;
case BusStep::Action::IncrementEffectiveAddress1: effective_address_[1] += 2; break; case BusStep::Action::IncrementEffectiveAddress1: effective_address_[1].full += 2; break;
case BusStep::Action::IncrementProgramCounter: program_counter_.full += 2; break; case BusStep::Action::IncrementProgramCounter: program_counter_.full += 2; break;
case BusStep::Action::AdvancePrefetch: case BusStep::Action::AdvancePrefetch:
prefetch_queue_.halves.high = prefetch_queue_.halves.low; prefetch_queue_.halves.high = prefetch_queue_.halves.low;

View File

@ -113,7 +113,7 @@ struct ProcessorStorageConstructor {
case 'f': // Fetch SSP LSW. case 'f': // Fetch SSP LSW.
step.microcycle.length = HalfCycles(5); step.microcycle.length = HalfCycles(5);
step.microcycle.operation = Microcycle::NewAddress | Microcycle::Read | Microcycle::IsProgram; // IsProgram is a guess. step.microcycle.operation = Microcycle::NewAddress | Microcycle::Read | Microcycle::IsProgram; // IsProgram is a guess.
step.microcycle.address = &storage_.effective_address_[0]; step.microcycle.address = &storage_.effective_address_[0].full;
step.microcycle.value = isupper(access_pattern[1]) ? &storage_.stack_pointers_[1].halves.high : &storage_.stack_pointers_[1].halves.low; step.microcycle.value = isupper(access_pattern[1]) ? &storage_.stack_pointers_[1].halves.high : &storage_.stack_pointers_[1].halves.low;
steps.push_back(step); steps.push_back(step);
@ -129,7 +129,7 @@ struct ProcessorStorageConstructor {
case 'v': // Fetch exception vector high. case 'v': // Fetch exception vector high.
step.microcycle.length = HalfCycles(5); step.microcycle.length = HalfCycles(5);
step.microcycle.operation = Microcycle::NewAddress | Microcycle::Read | Microcycle::IsProgram; // IsProgram is a guess. step.microcycle.operation = Microcycle::NewAddress | Microcycle::Read | Microcycle::IsProgram; // IsProgram is a guess.
step.microcycle.address = &storage_.effective_address_[0]; step.microcycle.address = &storage_.effective_address_[0].full;
step.microcycle.value = isupper(access_pattern[1]) ? &storage_.program_counter_.halves.high : &storage_.program_counter_.halves.low; step.microcycle.value = isupper(access_pattern[1]) ? &storage_.program_counter_.halves.high : &storage_.program_counter_.halves.low;
steps.push_back(step); steps.push_back(step);
@ -240,6 +240,7 @@ struct ProcessorStorageConstructor {
CMPI, // eight lowest bits are [size, mode, register], decoding to CMPI CMPI, // eight lowest bits are [size, mode, register], decoding to CMPI
BRA, // eight lowest bits are ignored, and an 'n np np' is scheduled BRA, // eight lowest bits are ignored, and an 'n np np' is scheduled
Bcc, // twelve lowest bits are ignored, only a PerformAction is scheduled Bcc, // twelve lowest bits are ignored, only a PerformAction is scheduled
LEA, // decodes register, mode, register
}; };
using Operation = ProcessorStorage::Operation; using Operation = ProcessorStorage::Operation;
@ -288,6 +289,7 @@ struct ProcessorStorageConstructor {
{0xff00, 0x6000, Operation::BRA, Decoder::BRA}, // 4-55 (p159) {0xff00, 0x6000, Operation::BRA, Decoder::BRA}, // 4-55 (p159)
{0xf000, 0x6000, Operation::Bcc, Decoder::Bcc}, // 4-25 (p129) {0xf000, 0x6000, Operation::Bcc, Decoder::Bcc}, // 4-25 (p129)
{0xf1c0, 0x41c0, Operation::MOVEAl, Decoder::LEA}, // 4-110 (p214)
}; };
std::vector<size_t> micro_op_pointers(65536, std::numeric_limits<size_t>::max()); std::vector<size_t> micro_op_pointers(65536, std::numeric_limits<size_t>::max());
@ -381,7 +383,7 @@ struct ProcessorStorageConstructor {
case 0x102: // CMPI.l #, (An) case 0x102: // CMPI.l #, (An)
case 0x103: // CMPI.l #, (An)+ case 0x103: // CMPI.l #, (An)+
op(Action::CopyDestinationToEffectiveAddress, seq("np")); op(Action::CopyDestinationToEffectiveAddress, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nR nr np", { &storage_.effective_address_[1] })); op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nR nr np", { &storage_.effective_address_[1].full }));
if(mode == 0x103) { if(mode == 0x103) {
op(int(Action::Increment4) | MicroOp::DestinationMask); op(int(Action::Increment4) | MicroOp::DestinationMask);
} }
@ -397,7 +399,7 @@ struct ProcessorStorageConstructor {
case 0x104: // CMPI.l #, -(An) case 0x104: // CMPI.l #, -(An)
op(int(Action::Decrement4) | MicroOp::DestinationMask, seq("np")); op(int(Action::Decrement4) | MicroOp::DestinationMask, seq("np"));
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np n")); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np n"));
op(Action::CopyDestinationToEffectiveAddress, seq("nR nr np", { &storage_.effective_address_[1] })); op(Action::CopyDestinationToEffectiveAddress, seq("nR nr np", { &storage_.effective_address_[1].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -408,8 +410,8 @@ struct ProcessorStorageConstructor {
case 0x005: // CMPI.bw #, (d16, An) case 0x005: // CMPI.bw #, (d16, An)
case 0x006: // CMPI.bw #, (d8, An, Xn) case 0x006: // CMPI.bw #, (d8, An, Xn)
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np")); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
op( calc_action_for_mode(destination_mode) | MicroOp::DestinationMask, op( calc_action_for_mode(mode) | MicroOp::DestinationMask,
seq(pseq("nr np"), { &storage_.effective_address_[1] }, !is_byte_access)); seq(pseq("nr np"), { &storage_.effective_address_[1].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -419,8 +421,8 @@ struct ProcessorStorageConstructor {
case 0x106: // CMPI.l #, (d8, An, Xn) case 0x106: // CMPI.l #, (d8, An, Xn)
op(Action::CopyDestinationToEffectiveAddress, seq("np")); op(Action::CopyDestinationToEffectiveAddress, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np")); op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
op( calc_action_for_mode(destination_mode) | MicroOp::DestinationMask, op( calc_action_for_mode(mode) | MicroOp::DestinationMask,
seq(pseq("np nR nr np"), { &storage_.effective_address_[1] })); seq(pseq("np nR nr np"), { &storage_.effective_address_[1].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -428,27 +430,27 @@ struct ProcessorStorageConstructor {
case 0x010: // CMPI.bw #, (xxx).w case 0x010: // CMPI.bw #, (xxx).w
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np")); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nr np", { &storage_.effective_address_[1] }, !is_byte_access)); op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nr np", { &storage_.effective_address_[1].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
case 0x110: // CMPI.l #, (xxx).w case 0x110: // CMPI.l #, (xxx).w
op(Action::None, seq("np")); op(Action::None, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np")); op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("nR nr np", { &storage_.effective_address_[1] })); op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("nR nr np", { &storage_.effective_address_[1].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
case 0x011: // CMPI.bw #, (xxx).l case 0x011: // CMPI.bw #, (xxx).l
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np")); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nr np", { &storage_.effective_address_[1] }, !is_byte_access)); op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nr np", { &storage_.effective_address_[1].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
case 0x111: // CMPI.l #, (xxx).l case 0x111: // CMPI.l #, (xxx).l
op(Action::None, seq("np")); op(Action::None, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np")); op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nR nr np", { &storage_.effective_address_[1] })); op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nR nr np", { &storage_.effective_address_[1].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -456,6 +458,54 @@ struct ProcessorStorageConstructor {
} }
} break; } break;
case Decoder::LEA: {
const int destination_register = (instruction >> 9) & 7;
storage_.instructions[instruction].destination = &storage_.address_[destination_register];
const int mode = combined_mode(source_mode, source_register);
switch(mode) {
default: continue;
case 0x04:
storage_.instructions[instruction].source = &storage_.address_[source_register];
break;
case 0x05: case 0x06: case 0x10:
case 0x11: case 0x12: case 0x13:
storage_.instructions[instruction].source = &storage_.effective_address_[0];
break;
}
switch(mode) {
default: break;
case 0x04: // LEA (An), An (i.e. MOVEA)
op(Action::PerformOperation, seq("np"));
op();
break;
case 0x05: // LEA (d16, An), An
case 0x12: // LEA (d16, PC), SR
op(calc_action_for_mode(mode) | MicroOp::SourceMask, seq("np np"));
op(Action::PerformOperation);
break;
case 0x06: // LEA (d8, An, Xn), SR
case 0x13: // LEA (d8, PC, Xn), SR
op(calc_action_for_mode(mode) | MicroOp::SourceMask, seq("n np n np"));
op(Action::PerformOperation);
break;
case 0x10: // LEA (xxx).W, An
op(int(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(Action::PerformOperation);
break;
case 0x11: // LEA (xxx).L, An
op(Action::None, seq("np"));
op(int(MicroOp::Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(Action::PerformOperation);
break;
}
} break;
case Decoder::MOVEtoSR: { case Decoder::MOVEtoSR: {
if(source_mode == 1) continue; if(source_mode == 1) continue;
storage_.instructions[instruction].set_source(storage_, source_mode, source_register); storage_.instructions[instruction].set_source(storage_, source_mode, source_register);
@ -489,7 +539,7 @@ struct ProcessorStorageConstructor {
case 0x13: // MOVE (d8, PC, Xn), SR case 0x13: // MOVE (d8, PC, Xn), SR
case 0x05: // MOVE (d16, An), SR case 0x05: // MOVE (d16, An), SR
case 0x06: // MOVE (d8, An, Xn), SR case 0x06: // MOVE (d8, An, Xn), SR
op(calc_action_for_mode(source_mode) | MicroOp::SourceMask, seq(pseq("np nr nn nn np"), { &storage_.effective_address_[0] })); op(calc_action_for_mode(mode) | MicroOp::SourceMask, seq(pseq("np nr nn nn np"), { &storage_.effective_address_[0].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -498,13 +548,13 @@ struct ProcessorStorageConstructor {
case 0x10: // MOVE (xxx).W, SR case 0x10: // MOVE (xxx).W, SR
op( op(
int(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask, int(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask,
seq("np nr nn nn np", { &storage_.effective_address_[0] })); seq("np nr nn nn np", { &storage_.effective_address_[0].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
case 0x11: // MOVE (xxx).L, SR case 0x11: // MOVE (xxx).L, SR
op(Action::None, seq("np")); op(Action::None, seq("np"));
op(int(MicroOp::Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask, seq("np nr", { &storage_.effective_address_[0] })); op(int(MicroOp::Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask, seq("np nr", { &storage_.effective_address_[0].full }));
op(Action::PerformOperation, seq("nn nn np")); op(Action::PerformOperation, seq("nn nn np"));
op(); op();
break; break;
@ -666,7 +716,7 @@ struct ProcessorStorageConstructor {
operation = Operation::MOVEAl; operation = Operation::MOVEAl;
case 0x10200: // MOVE.l (An), Dn case 0x10200: // MOVE.l (An), Dn
case 0x10300: // MOVE.l (An)+, Dn case 0x10300: // MOVE.l (An)+, Dn
op(Action::CopySourceToEffectiveAddress, seq("nR nr np", { &storage_.effective_address_[0] })); op(Action::CopySourceToEffectiveAddress, seq("nR nr np", { &storage_.effective_address_[0].full }));
if(source_mode == 0x3) { if(source_mode == 0x3) {
op(int(Action::Increment4) | MicroOp::SourceMask); op(int(Action::Increment4) | MicroOp::SourceMask);
} }
@ -694,8 +744,8 @@ struct ProcessorStorageConstructor {
case 0x10203: // MOVE.l (An), (An)+ case 0x10203: // MOVE.l (An), (An)+
case 0x10303: // MOVE.l (An)+, (An)+ case 0x10303: // MOVE.l (An)+, (An)+
op(Action::CopyDestinationToEffectiveAddress); op(Action::CopyDestinationToEffectiveAddress);
op(Action::CopySourceToEffectiveAddress, seq("nR nr", { &storage_.effective_address_[0] })); op(Action::CopySourceToEffectiveAddress, seq("nR nr", { &storage_.effective_address_[0].full }));
op(Action::PerformOperation, seq("nW nw np", { &storage_.effective_address_[1] })); op(Action::PerformOperation, seq("nW nw np", { &storage_.effective_address_[1].full }));
if(source_mode == 0x3 || destination_mode == 0x3) { if(source_mode == 0x3 || destination_mode == 0x3) {
op( op(
int(Action::Increment4) | int(Action::Increment4) |
@ -780,7 +830,7 @@ struct ProcessorStorageConstructor {
operation = Operation::MOVEAw; operation = Operation::MOVEAw;
case 0x0500: // MOVE (d16, An), Dn case 0x0500: // MOVE (d16, An), Dn
case 0x0600: // MOVE (d8, An, Xn), Dn case 0x0600: // MOVE (d8, An, Xn), Dn
op(action_calc() | MicroOp::SourceMask, seq(pseq("np nr np"), { &storage_.effective_address_[0] }, !is_byte_access)); op(action_calc() | MicroOp::SourceMask, seq(pseq("np nr np"), { &storage_.effective_address_[0].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -834,7 +884,7 @@ struct ProcessorStorageConstructor {
case 0x1000: // MOVE (xxx).W, Dn case 0x1000: // MOVE (xxx).W, Dn
op( op(
int(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask, int(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask,
seq("np nr np", { &storage_.effective_address_[0] }, !is_byte_access)); seq("np nr np", { &storage_.effective_address_[0].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -871,7 +921,7 @@ struct ProcessorStorageConstructor {
operation = Operation::MOVEAw; operation = Operation::MOVEAw;
case 0x1100: // MOVE (xxx).L, Dn case 0x1100: // MOVE (xxx).L, Dn
op(Action::None, seq("np")); op(Action::None, seq("np"));
op(int(MicroOp::Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask, seq("np nr", { &storage_.effective_address_[0] }, !is_byte_access)); op(int(MicroOp::Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask, seq("np nr", { &storage_.effective_address_[0].full }, !is_byte_access));
op(Action::PerformOperation, seq("np")); op(Action::PerformOperation, seq("np"));
op(); op();
break; break;
@ -881,7 +931,7 @@ struct ProcessorStorageConstructor {
// //
case 0x1200: // MOVE (d16, PC), Dn case 0x1200: // MOVE (d16, PC), Dn
op(int(Action::CalcD16PC) | MicroOp::SourceMask, seq("n np nr np", { &storage_.effective_address_[0] }, !is_byte_access)); op(int(Action::CalcD16PC) | MicroOp::SourceMask, seq("n np nr np", { &storage_.effective_address_[0].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -890,7 +940,7 @@ struct ProcessorStorageConstructor {
// //
case 0x1300: // MOVE (d8, An, Xn), Dn case 0x1300: // MOVE (d8, An, Xn), Dn
op(int(Action::CalcD8PCXn) | MicroOp::SourceMask, seq("n np nr np", { &storage_.effective_address_[0] }, !is_byte_access)); op(int(Action::CalcD8PCXn) | MicroOp::SourceMask, seq("n np nr np", { &storage_.effective_address_[0].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;

View File

@ -36,7 +36,7 @@ class ProcessorStorage {
// Generic sources and targets for memory operations; // Generic sources and targets for memory operations;
// by convention: [0] = source, [1] = destination. // by convention: [0] = source, [1] = destination.
uint32_t effective_address_[2]; RegisterPair32 effective_address_[2];
RegisterPair32 bus_data_[2]; RegisterPair32 bus_data_[2];
HalfCycles half_cycles_left_to_run_; HalfCycles half_cycles_left_to_run_;
@ -52,7 +52,7 @@ class ProcessorStorage {
CMPb, CMPw, CMPl, CMPb, CMPw, CMPl,
BRA, Bcc BRA, Bcc,
}; };
/*! /*!