1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-21 05:29:13 +00:00

Switches to a more explicit tokeniser, to allow for greater flexibility momentarily.

This commit is contained in:
Thomas Harte 2019-03-30 23:11:39 -04:00
parent bc6349f823
commit cb240cd32a

View File

@ -9,6 +9,7 @@
#include "../68000.hpp" #include "../68000.hpp"
#include <algorithm> #include <algorithm>
#include <sstream>
namespace CPU { namespace CPU {
namespace MC68000 { namespace MC68000 {
@ -79,44 +80,35 @@ struct ProcessorStorageConstructor {
The user should fill in the steps necessary to get data into or extract The user should fill in the steps necessary to get data into or extract
data from those. data from those.
*/ */
size_t assemble_program(const char *access_pattern, const std::vector<uint32_t *> &addresses = {}, bool read_full_words = true) { size_t assemble_program(std::string access_pattern, const std::vector<uint32_t *> &addresses = {}, bool read_full_words = true) {
auto address_iterator = addresses.begin(); auto address_iterator = addresses.begin();
RegisterPair32 *scratch_data_read = storage_.bus_data_; RegisterPair32 *scratch_data_read = storage_.bus_data_;
RegisterPair32 *scratch_data_write = storage_.bus_data_; RegisterPair32 *scratch_data_write = storage_.bus_data_;
using Action = BusStep::Action; using Action = BusStep::Action;
std::vector<BusStep> steps; std::vector<BusStep> steps;
std::stringstream stream(access_pattern);
// Parse the access pattern to build microcycles. // Tokenise the access pattern by splitting on spaces.
while(*access_pattern) { std::string token;
while(stream >> token) {
ProcessorBase::BusStep step; ProcessorBase::BusStep step;
switch(*access_pattern) { // Do nothing (possibly twice).
case '\t': case ' ': // White space acts as a no-op; it's for clarity only. if(token == "n" || token == "nn") {
++access_pattern;
break;
case 'n': // This might be a plain NOP cycle, in which some internal calculation occurs,
// or it might pair off with something afterwards.
switch(access_pattern[1]) {
default: // This is probably a pure NOP; if what comes after this 'n' isn't actually
// valid, it should be caught in the outer switch the next time around the loop.
steps.push_back(step); steps.push_back(step);
++access_pattern; if(token.size() == 2) {
break;
case '-': // This is two NOPs in a row.
steps.push_back(step); steps.push_back(step);
steps.push_back(step); }
access_pattern += 2; continue;
break; }
case 'F': // Fetch SSP MSW. // Fetch SSP.
case 'f': // Fetch SSP LSW. if(token == "nF" || token == "nf") {
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].full; 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(token[1]) ? &storage_.stack_pointers_[1].halves.high : &storage_.stack_pointers_[1].halves.low;
steps.push_back(step); steps.push_back(step);
step.microcycle.length = HalfCycles(3); step.microcycle.length = HalfCycles(3);
@ -124,15 +116,15 @@ struct ProcessorStorageConstructor {
step.action = Action::IncrementEffectiveAddress0; step.action = Action::IncrementEffectiveAddress0;
steps.push_back(step); steps.push_back(step);
access_pattern += 2; continue;
break; }
case 'V': // Fetch exception vector low. // Fetch exception vector.
case 'v': // Fetch exception vector high. if(token == "nV" || token == "nv") {
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].full; 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(token[1]) ? &storage_.program_counter_.halves.high : &storage_.program_counter_.halves.low;
steps.push_back(step); steps.push_back(step);
step.microcycle.length = HalfCycles(3); step.microcycle.length = HalfCycles(3);
@ -140,10 +132,11 @@ struct ProcessorStorageConstructor {
step.action = Action::IncrementEffectiveAddress0; step.action = Action::IncrementEffectiveAddress0;
steps.push_back(step); steps.push_back(step);
access_pattern += 2; continue;
break; }
case 'p': // Fetch from the program counter into the prefetch queue. // Fetch from the program counter into the prefetch queue.
if(token == "np") {
step.microcycle.length = HalfCycles(5); step.microcycle.length = HalfCycles(5);
step.microcycle.operation = Microcycle::NewAddress | Microcycle::Read | Microcycle::IsProgram; step.microcycle.operation = Microcycle::NewAddress | Microcycle::Read | Microcycle::IsProgram;
step.microcycle.address = &storage_.program_counter_.full; step.microcycle.address = &storage_.program_counter_.full;
@ -156,28 +149,35 @@ struct ProcessorStorageConstructor {
step.action = Action::IncrementProgramCounter; step.action = Action::IncrementProgramCounter;
steps.push_back(step); steps.push_back(step);
access_pattern += 2; continue;
break; }
case 'r': // Fetch LSW (or only) word (/byte) // The reset cycle.
case 'R': // Fetch MSW word if(token == "_") {
case 'w': // Store LSW (or only) word (/byte) step.microcycle.length = HalfCycles(248);
case 'W': { // Store MSW word step.microcycle.operation = Microcycle::Reset;
steps.push_back(step);
continue;
}
// A standard read or write.
if(token == "nR" || token == "nr" || token == "nW" || token == "nw") {
const bool is_read = tolower(access_pattern[1]) == 'r'; const bool is_read = tolower(access_pattern[1]) == 'r';
RegisterPair32 **scratch_data = is_read ? &scratch_data_read : &scratch_data_write; RegisterPair32 **scratch_data = is_read ? &scratch_data_read : &scratch_data_write;
step.microcycle.length = HalfCycles(5); step.microcycle.length = HalfCycles(5);
step.microcycle.operation = Microcycle::NewAddress | (is_read ? Microcycle::Read : 0); step.microcycle.operation = Microcycle::NewAddress | (is_read ? Microcycle::Read : 0);
step.microcycle.address = *address_iterator; step.microcycle.address = *address_iterator;
step.microcycle.value = isupper(access_pattern[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); steps.push_back(step);
step.microcycle.length = HalfCycles(3); step.microcycle.length = HalfCycles(3);
step.microcycle.operation |= (read_full_words ? Microcycle::SelectWord : Microcycle::SelectByte) | (is_read ? Microcycle::Read : 0); step.microcycle.operation |= (read_full_words ? Microcycle::SelectWord : Microcycle::SelectByte) | (is_read ? Microcycle::Read : 0);
if(access_pattern[1] == 'R') { if(token[1] == 'R') {
step.action = Action::IncrementEffectiveAddress0; step.action = Action::IncrementEffectiveAddress0;
} }
if(access_pattern[1] == 'W') { if(token[1] == 'W') {
step.action = Action::IncrementEffectiveAddress1; step.action = Action::IncrementEffectiveAddress1;
} }
steps.push_back(step); steps.push_back(step);
@ -186,23 +186,13 @@ struct ProcessorStorageConstructor {
++(*scratch_data); ++(*scratch_data);
++address_iterator; ++address_iterator;
} }
access_pattern += 2;
} break; continue;
} }
break;
case '_': // Indicates the reset cycle. std::cerr << "MC68000 program builder; Unknown access token " << token << std::endl;
step.microcycle.length = HalfCycles(248);
step.microcycle.operation = Microcycle::Reset;
steps.push_back(step);
++access_pattern;
break;
default:
std::cerr << "MC68000 program builder; Unknown access type " << *access_pattern << std::endl;
assert(false); assert(false);
} }
}
// Add a final 'ScheduleNextProgram' sentinel. // Add a final 'ScheduleNextProgram' sentinel.
BusStep end_program; BusStep end_program;