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

Corrects CMPI and documentation; implements JMP.

This commit is contained in:
Thomas Harte 2019-03-31 21:13:26 -04:00
parent cb240cd32a
commit c6f977ed4b
3 changed files with 132 additions and 54 deletions

View File

@ -196,6 +196,11 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80000000;
} break;
// JMP: copies the source to the program counter.
case Operation::JMP:
program_counter_.full = active_program_->source->full;
break;
/*
MOVE.b, MOVE.l and MOVE.w: move the least significant byte or word, or the entire long word,
and set negative, zero, overflow and carry as appropriate.
@ -364,6 +369,19 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
}
break;
case int(MicroOp::Action::CalcD16PC) | MicroOp::SourceMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.low.full) + program_counter_.full;
break;
case int(MicroOp::Action::CalcD16PC) | MicroOp::DestinationMask:
effective_address_[1] = int16_t(prefetch_queue_.halves.low.full) + program_counter_.full;
break;
case int(MicroOp::Action::CalcD16PC) | MicroOp::SourceMask | MicroOp::DestinationMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.high.full) + program_counter_.full;
effective_address_[1] = int16_t(prefetch_queue_.halves.low.full) + program_counter_.full;
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::SourceMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.low.full) + active_program_->source->full;
break;
@ -422,19 +440,32 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
case int(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask:
// Assumption: this will be assembling right at the start of the instruction.
bus_data_[0] = prefetch_queue_.halves.low.full;
source_bus_data_[0] = prefetch_queue_.halves.low.full;
break;
case int(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::DestinationMask:
bus_data_[1] = prefetch_queue_.halves.low.full;
destination_bus_data_[0] = prefetch_queue_.halves.low.full;
break;
case int(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask:
bus_data_[0] = prefetch_queue_.full;
source_bus_data_[0] = prefetch_queue_.full;
break;
case int(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::DestinationMask:
bus_data_[1] = prefetch_queue_.full;
destination_bus_data_[0] = prefetch_queue_.full;
break;
case int(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::SourceMask:
effective_address_[0] = *active_program_->source;
break;
case int(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::DestinationMask:
effective_address_[1] = *active_program_->destination;
break;
case int(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::SourceMask | MicroOp::DestinationMask:
effective_address_[0] = *active_program_->source;
effective_address_[1] = *active_program_->destination;
break;
}

View File

@ -47,26 +47,35 @@ struct ProcessorStorageConstructor {
during this program. This should follow the same general pattern as
those in yacht.txt; full description below.
@discussion
The access pattern is defined, as in yacht.txt, to be a string consisting
of the following discrete bus actions. Spaces are ignored.
@param addresses A vector of the addresses to place on the bus coincident
with those acess steps that require them.
* n: no operation; data bus is not used;
* -: idle state; data bus is not used but is also not available;
* p: program fetch; reads from the PC and adds two to it;
* W: write MSW of something onto the bus;
* w: write LSW of something onto the bus;
* R: read MSW of something from the bus;
* r: read LSW of soemthing from the bus;
* S: push the MSW of something onto the stack;
* s: push the LSW of something onto the stack;
* U: pop the MSW of something from the stack;
* u: pop the LSW of something from the stack;
* V: fetch a vector's MSW;
* v: fetch a vector's LSW;
@param read_full_words @c true to indicate that read and write operations are
selecting a full word; @c false to signal byte accesses only.
@discussion
The access pattern is defined to correlate closely to that in yacht.txt; it is
a space-separated sequence of the following actions:
* n: no operation for four cycles; data bus is not used;
* nn: no operation for eight cycles; data bus is not used;
* np: program fetch; reads from the PC and adds two to it, advancing the prefetch queue;
* nW: write MSW of something onto the bus;
* nw: write LSW of something onto the bus;
* nR: read MSW of something from the bus into the source latch;
* nr: read LSW of soemthing from the bus into the source latch;
* nRd: read MSW of something from the bus into the destination latch;
* nrd: read LSW of soemthing from the bus into the destination latch;
* nS: push the MSW of something onto the stack;
* ns: push the LSW of something onto the stack;
* nU: pop the MSW of something from the stack;
* nu: pop the LSW of something from the stack;
* nV: fetch a vector's MSW;
* nv: fetch a vector's LSW;
* i: acquire interrupt vector in an IACK cycle;
* F: fetch the SSPs MSW;
* f: fetch the SSP's LSW.
* nF: fetch the SSPs MSW;
* nf: fetch the SSP's LSW;
* _: hold the reset line active for the usual period.
Quite a lot of that is duplicative, implying both something about internal
state and something about what's observable on the bus, but it's helpful to
@ -82,8 +91,6 @@ struct ProcessorStorageConstructor {
*/
size_t assemble_program(std::string access_pattern, const std::vector<uint32_t *> &addresses = {}, bool read_full_words = true) {
auto address_iterator = addresses.begin();
RegisterPair32 *scratch_data_read = storage_.bus_data_;
RegisterPair32 *scratch_data_write = storage_.bus_data_;
using Action = BusStep::Action;
std::vector<BusStep> steps;
@ -162,14 +169,15 @@ struct ProcessorStorageConstructor {
}
// A standard read or write.
if(token == "nR" || token == "nr" || token == "nW" || token == "nw") {
const bool is_read = tolower(access_pattern[1]) == 'r';
RegisterPair32 **scratch_data = is_read ? &scratch_data_read : &scratch_data_write;
if(token == "nR" || token == "nr" || token == "nW" || token == "nw" || token == "nRd" || token == "nrd") {
const bool is_read = tolower(token[1]) == 'r';
const bool use_source_storage = is_read && token.size() != 3;
RegisterPair32 *scratch_data = use_source_storage ? &storage_.source_bus_data_[0] : &storage_.destination_bus_data_[0];
step.microcycle.length = HalfCycles(5);
step.microcycle.operation = Microcycle::NewAddress | (is_read ? Microcycle::Read : 0);
step.microcycle.address = *address_iterator;
step.microcycle.value = isupper(token[1]) ? &(*scratch_data)->halves.high : &(*scratch_data)->halves.low;
step.microcycle.value = isupper(token[1]) ? &scratch_data->halves.high : &scratch_data->halves.low;
steps.push_back(step);
step.microcycle.length = HalfCycles(3);
@ -182,8 +190,7 @@ struct ProcessorStorageConstructor {
}
steps.push_back(step);
if(!isupper(access_pattern[1])) {
++(*scratch_data);
if(!isupper(token[1])) {
++address_iterator;
}
@ -241,7 +248,8 @@ struct ProcessorStorageConstructor {
Bcc, // twelve lowest bits are ignored, only a PerformAction is scheduled
LEA, // decodes register, mode, register
MOVEq, // decodes just a destination register
RESET, // no further decoding applied
RESET, // no further decoding applied, performs reset cycle
JMP, // six lowest bits are [mode, register], decoding to JMP
};
using Operation = ProcessorStorage::Operation;
@ -294,6 +302,8 @@ struct ProcessorStorageConstructor {
{0xf100, 0x7000, Operation::MOVEq, Decoder::MOVEq}, // 4-134 (p238)
{0xffff, 0x4e70, Operation::None, Decoder::RESET}, // 6-83 (p537)
{0xffc0, 0x4ec0, Operation::JMP, Decoder::JMP}, // 4-108 (p212)
};
std::vector<size_t> micro_op_pointers(65536, std::numeric_limits<size_t>::max());
@ -335,8 +345,8 @@ struct ProcessorStorageConstructor {
const int source = instruction & 7;
if(instruction & 8) {
storage_.instructions[instruction].source = &storage_.bus_data_[0];
storage_.instructions[instruction].destination = &storage_.bus_data_[1];
storage_.instructions[instruction].source = &storage_.source_bus_data_[0];
storage_.instructions[instruction].destination = &storage_.destination_bus_data_[0];
op( int(Action::Decrement1) | MicroOp::SourceMask | MicroOp::DestinationMask,
seq("n nr nr np nw", { &storage_.address_[source].full, &storage_.address_[destination].full, &storage_.address_[destination].full }, false));
@ -355,7 +365,7 @@ struct ProcessorStorageConstructor {
const auto destination_mode = source_mode;
const auto destination_register = source_register;
storage_.instructions[instruction].source = &storage_.bus_data_[0];
storage_.instructions[instruction].source = &storage_.source_bus_data_[0];
storage_.instructions[instruction].set_destination(storage_, destination_mode, destination_register);
const bool is_byte_access = mapping.operation == Operation::CMPb;
@ -375,7 +385,7 @@ struct ProcessorStorageConstructor {
case 0x002: // CMPI.bw #, (An)
case 0x003: // CMPI.bw #, (An)+
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nr np", { &storage_.address_[destination_register].full }, !is_byte_access));
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nrd np", { &storage_.address_[destination_register].full }, !is_byte_access));
if(mode == 0x3) {
op(int(is_byte_access ? Action::Increment1 : Action::Increment2) | MicroOp::DestinationMask);
}
@ -385,7 +395,7 @@ struct ProcessorStorageConstructor {
case 0x102: // CMPI.l #, (An)
case 0x103: // CMPI.l #, (An)+
op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nR nr np", { &storage_.effective_address_[1].full }));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nRd nrd np", { &storage_.effective_address_[1].full }));
if(mode == 0x103) {
op(int(Action::Increment4) | MicroOp::DestinationMask);
}
@ -394,14 +404,14 @@ struct ProcessorStorageConstructor {
case 0x004: // CMPI.bw #, -(An)
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np n"));
op(int(is_byte_access ? Action::Decrement1 : Action::Decrement1) | MicroOp::DestinationMask, seq("nr np", { &storage_.address_[destination_register].full }));
op(int(is_byte_access ? Action::Decrement1 : Action::Decrement1) | MicroOp::DestinationMask, seq("nrd np", { &storage_.address_[destination_register].full }));
op(Action::PerformOperation);
break;
case 0x104: // CMPI.l #, -(An)
op(int(Action::Decrement4) | MicroOp::DestinationMask, seq("np"));
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np n"));
op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("nR nr np", { &storage_.effective_address_[1].full }));
op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("nRd nrd np", { &storage_.effective_address_[1].full }));
op(Action::PerformOperation);
break;
@ -411,7 +421,7 @@ struct ProcessorStorageConstructor {
case 0x006: // CMPI.bw #, (d8, An, Xn)
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
op( calc_action_for_mode(mode) | MicroOp::DestinationMask,
seq(pseq("nr np", mode), { &storage_.effective_address_[1].full }, !is_byte_access));
seq(pseq("nrd np", mode), { &storage_.effective_address_[1].full }, !is_byte_access));
op(Action::PerformOperation);
break;
@ -422,33 +432,33 @@ struct ProcessorStorageConstructor {
op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
op( calc_action_for_mode(mode) | MicroOp::DestinationMask,
seq(pseq("np nR nr np", mode), { &storage_.effective_address_[1].full }));
seq(pseq("np nRd nrd np", mode), { &storage_.effective_address_[1].full }));
op(Action::PerformOperation);
break;
case 0x010: // CMPI.bw #, (xxx).w
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nr np", { &storage_.effective_address_[1].full }, !is_byte_access));
op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nrd np", { &storage_.effective_address_[1].full }, !is_byte_access));
op(Action::PerformOperation);
break;
case 0x110: // CMPI.l #, (xxx).w
op(Action::None, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("nR nr np", { &storage_.effective_address_[1].full }));
op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("nRd nrd np", { &storage_.effective_address_[1].full }));
op(Action::PerformOperation);
break;
case 0x011: // CMPI.bw #, (xxx).l
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nr np", { &storage_.effective_address_[1].full }, !is_byte_access));
op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nrd np", { &storage_.effective_address_[1].full }, !is_byte_access));
op(Action::PerformOperation);
break;
case 0x111: // CMPI.l #, (xxx).l
op(Action::None, seq("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].full }));
op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nRd nrd np", { &storage_.effective_address_[1].full }));
op(Action::PerformOperation);
break;
@ -456,6 +466,41 @@ struct ProcessorStorageConstructor {
}
} break;
case Decoder::JMP: {
storage_.instructions[instruction].source = &storage_.effective_address_[0];
const int mode = combined_mode(source_mode, source_register);
switch(mode) {
default: continue;
case 0x02: // JMP (An)
storage_.instructions[instruction].source = &storage_.address_[source_register];
op(Action::PerformOperation, seq("np np"));
break;
case 0x12: // JMP (d16, PC)
case 0x05: // JMP (d16, An)
op(calc_action_for_mode(mode) | MicroOp::SourceMask, seq("n np np", { &storage_.effective_address_[0].full }));
op(Action::PerformOperation);
break;
case 0x13: // JMP (d8, PC, Xn)
case 0x06: // JMP (d8, An, Xn)
op(calc_action_for_mode(mode) | MicroOp::SourceMask, seq("n nn np np", { &storage_.effective_address_[0].full }));
op(Action::PerformOperation);
break;
case 0x10: // JMP (xxx).W
op(int(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask);
op(Action::PerformOperation, seq("n np np"));
break;
case 0x11: // JMP (xxx).L
op(Action::None, seq("np"));
op(int(MicroOp::Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask);
op(Action::PerformOperation, seq("np np"));
break;
}
} break;
case Decoder::LEA: {
const int destination_register = (instruction >> 9) & 7;
storage_.instructions[instruction].destination = &storage_.address_[destination_register];
@ -581,7 +626,7 @@ struct ProcessorStorageConstructor {
break;
default: // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L
storage_.instructions[instruction].source = &storage_.bus_data_[0];
storage_.instructions[instruction].source = &storage_.source_bus_data_[0];
break;
}
@ -595,7 +640,7 @@ struct ProcessorStorageConstructor {
break;
default: // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L
storage_.instructions[instruction].destination = &storage_.bus_data_[1];
storage_.instructions[instruction].destination = &storage_.destination_bus_data_[0];
break;
}
@ -1126,6 +1171,7 @@ struct ProcessorStorageConstructor {
} break;
case Decoder::RESET:
storage_.instructions[instruction].requires_supervisor = true;
op(Action::None, seq("nn _ np"));
break;

View File

@ -37,7 +37,8 @@ class ProcessorStorage {
// Generic sources and targets for memory operations;
// by convention: [0] = source, [1] = destination.
RegisterPair32 effective_address_[2];
RegisterPair32 bus_data_[2];
RegisterPair32 source_bus_data_[1];
RegisterPair32 destination_bus_data_[1];
HalfCycles half_cycles_left_to_run_;
@ -53,7 +54,7 @@ class ProcessorStorage {
CMPb, CMPw, CMPl,
BRA, Bcc,
BRA, Bcc, JMP
};
/*!
@ -209,17 +210,17 @@ class ProcessorStorage {
void set_source(ProcessorStorage &storage, int mode, int reg) {
switch(mode) {
case 0: source = &storage.data_[reg]; break;
case 1: source = &storage.address_[reg]; break;
default: source = &storage.bus_data_[0]; break;
case 0: source = &storage.data_[reg]; break;
case 1: source = &storage.address_[reg]; break;
default: source = &storage.source_bus_data_[0]; break;
}
}
void set_destination(ProcessorStorage &storage, int mode, int reg) {
switch(mode) {
case 0: destination = &storage.data_[reg]; break;
case 1: destination = &storage.address_[reg]; break;
default: destination = &storage.bus_data_[1]; break;
case 0: destination = &storage.data_[reg]; break;
case 1: destination = &storage.address_[reg]; break;
default: destination = &storage.destination_bus_data_[0]; break;
}
}
};