mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 01:31:42 +00:00
This is where my thinking now resides. Two levels of indirection, and consolidated collections.
This commit is contained in:
parent
33b53e7605
commit
57898ed6dd
@ -9,17 +9,34 @@
|
|||||||
template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>::run_for(HalfCycles duration) {
|
template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>::run_for(HalfCycles duration) {
|
||||||
// TODO: obey the 'cycles' count.
|
// TODO: obey the 'cycles' count.
|
||||||
while(true) {
|
while(true) {
|
||||||
// Check whether the program is exhausted.
|
// Check whether the current list of bus steps is exhausted; if so then
|
||||||
if(active_program_->action == Step::Action::ScheduleNextProgram) {
|
// seek out another one from the current program (if any), and if there
|
||||||
std::cerr << "68000 Abilities exhausted" << std::endl;
|
// are no more to do, revert to scheduling something else (after checking
|
||||||
return;
|
// for interrupts).
|
||||||
|
if(active_step_->action == BusStep::Action::ScheduleNextProgram) {
|
||||||
|
if(active_micro_op_) {
|
||||||
|
++active_micro_op_;
|
||||||
|
switch(active_micro_op_->action) {
|
||||||
|
case MicroOp::Action::None: break;
|
||||||
|
|
||||||
|
case MicroOp::Action::PerformOperation:
|
||||||
|
std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
active_step_ = active_micro_op_->bus_program;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!active_step_) {
|
||||||
|
std::cerr << "68000 Abilities exhausted; should schedule an instruction or something?" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The program is not exhausted, so perform the microcycle.
|
// The bus step list is not exhausted, so perform the microcycle.
|
||||||
|
|
||||||
// Check for DTack if this isn't being treated implicitly.
|
// Check for DTack if this isn't being treated implicitly.
|
||||||
if(!dtack_is_implicit) {
|
if(!dtack_is_implicit) {
|
||||||
if(active_program_->microcycle.operation & (Microcycle::UpperData | Microcycle::LowerData) && !dtack_) {
|
if(active_step_->microcycle.operation & (Microcycle::UpperData | Microcycle::LowerData) && !dtack_) {
|
||||||
// TODO: perform wait state.
|
// TODO: perform wait state.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -28,26 +45,26 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
|||||||
// TODO: synchronous bus.
|
// TODO: synchronous bus.
|
||||||
|
|
||||||
// Perform the microcycle.
|
// Perform the microcycle.
|
||||||
bus_handler_.perform_bus_operation(active_program_->microcycle, is_supervisor_);
|
bus_handler_.perform_bus_operation(active_step_->microcycle, is_supervisor_);
|
||||||
|
|
||||||
// Perform the post-hoc action.
|
// Perform the post-hoc action.
|
||||||
switch(active_program_->action) {
|
switch(active_step_->action) {
|
||||||
default:
|
default:
|
||||||
std::cerr << "Unimplemented 68000 action: " << int(active_program_->action) << std::endl;
|
std::cerr << "Unimplemented 68000 bus step action: " << int(active_step_->action) << std::endl;
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Step::Action::None: break;
|
case BusStep::Action::None: break;
|
||||||
|
|
||||||
case Step::Action::IncrementEffectiveAddress: effective_address_ += 2; break;
|
case BusStep::Action::IncrementEffectiveAddress: effective_address_ += 2; break;
|
||||||
case Step::Action::IncrementProgramCounter: program_counter_.full += 2; break;
|
case BusStep::Action::IncrementProgramCounter: program_counter_.full += 2; break;
|
||||||
|
|
||||||
case Step::Action::AdvancePrefetch:
|
case BusStep::Action::AdvancePrefetch:
|
||||||
prefetch_queue_[0] = prefetch_queue_[1];
|
prefetch_queue_[0] = prefetch_queue_[1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move to the next program step.
|
// Move to the next program step.
|
||||||
++active_program_;
|
++active_step_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,32 +8,35 @@
|
|||||||
|
|
||||||
#include "../68000.hpp"
|
#include "../68000.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
using namespace CPU::MC68000;
|
using namespace CPU::MC68000;
|
||||||
|
|
||||||
ProcessorStorage::ProcessorStorage() {
|
ProcessorStorage::ProcessorStorage() {
|
||||||
// Create the reset program.
|
// Create the exception programs.
|
||||||
reset_program_ = assemble_program("n- n- n- n- n- nn nF nf nV nv np np");
|
const size_t reset_offset = assemble_program("n- n- n- n- n- nn nF nf nV nv np np");
|
||||||
|
|
||||||
// TODO: install access patterns.
|
// Install all necessary access patterns.
|
||||||
|
const BusStepCollection bus_steps = assemble_standard_bus_steps();
|
||||||
|
|
||||||
// Install operations.
|
// Install operations.
|
||||||
for(int c = 0; c < 65536; ++c) {
|
install_instructions(bus_steps);
|
||||||
install_instruction(c);
|
|
||||||
}
|
// Realise the exception programs as direct pointers.
|
||||||
|
reset_program_ = &all_bus_steps_[reset_offset];
|
||||||
|
|
||||||
// Set initial state. Largely TODO.
|
// Set initial state. Largely TODO.
|
||||||
active_program_ = reset_program_.data();
|
active_step_ = reset_program_;
|
||||||
effective_address_ = 0;
|
effective_address_ = 0;
|
||||||
is_supervisor_ = 1;
|
is_supervisor_ = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: allow actions to be specified, of course.
|
size_t ProcessorStorage::assemble_program(const char *access_pattern) {
|
||||||
std::vector<ProcessorStorage::Step> ProcessorStorage::assemble_program(const char *access_pattern) {
|
const size_t start = all_bus_steps_.size();
|
||||||
std::vector<Step> steps;
|
|
||||||
|
|
||||||
// Parse the access pattern to build microcycles.
|
// Parse the access pattern to build microcycles.
|
||||||
while(*access_pattern) {
|
while(*access_pattern) {
|
||||||
Step step;
|
BusStep step;
|
||||||
|
|
||||||
switch(*access_pattern) {
|
switch(*access_pattern) {
|
||||||
case '\t': case ' ': // White space acts as a no-op; it's for clarity only.
|
case '\t': case ' ': // White space acts as a no-op; it's for clarity only.
|
||||||
@ -45,13 +48,13 @@ std::vector<ProcessorStorage::Step> ProcessorStorage::assemble_program(const cha
|
|||||||
switch(access_pattern[1]) {
|
switch(access_pattern[1]) {
|
||||||
default: // This is probably a pure NOP; if what comes after this 'n' isn't actually
|
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.
|
// valid, it should be caught in the outer switch the next time around the loop.
|
||||||
steps.push_back(step);
|
all_bus_steps_.push_back(step);
|
||||||
++access_pattern;
|
++access_pattern;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '-': // This is two NOPs in a row.
|
case '-': // This is two NOPs in a row.
|
||||||
steps.push_back(step);
|
all_bus_steps_.push_back(step);
|
||||||
steps.push_back(step);
|
all_bus_steps_.push_back(step);
|
||||||
access_pattern += 2;
|
access_pattern += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -61,12 +64,12 @@ std::vector<ProcessorStorage::Step> ProcessorStorage::assemble_program(const cha
|
|||||||
step.microcycle.operation = Microcycle::Address | Microcycle::ReadWrite | Microcycle::IsProgram; // IsProgram is a guess.
|
step.microcycle.operation = Microcycle::Address | Microcycle::ReadWrite | Microcycle::IsProgram; // IsProgram is a guess.
|
||||||
step.microcycle.address = &effective_address_;
|
step.microcycle.address = &effective_address_;
|
||||||
step.microcycle.value = isupper(access_pattern[1]) ? &stack_pointers_[1].halves.high : &stack_pointers_[1].halves.low;
|
step.microcycle.value = isupper(access_pattern[1]) ? &stack_pointers_[1].halves.high : &stack_pointers_[1].halves.low;
|
||||||
steps.push_back(step);
|
all_bus_steps_.push_back(step);
|
||||||
|
|
||||||
step.microcycle.length = HalfCycles(3);
|
step.microcycle.length = HalfCycles(3);
|
||||||
step.microcycle.operation |= Microcycle::LowerData | Microcycle::UpperData;
|
step.microcycle.operation |= Microcycle::LowerData | Microcycle::UpperData;
|
||||||
step.action = Step::Action::IncrementEffectiveAddress;
|
step.action = BusStep::Action::IncrementEffectiveAddress;
|
||||||
steps.push_back(step);
|
all_bus_steps_.push_back(step);
|
||||||
|
|
||||||
access_pattern += 2;
|
access_pattern += 2;
|
||||||
break;
|
break;
|
||||||
@ -77,12 +80,12 @@ std::vector<ProcessorStorage::Step> ProcessorStorage::assemble_program(const cha
|
|||||||
step.microcycle.operation = Microcycle::Address | Microcycle::ReadWrite | Microcycle::IsProgram; // IsProgram is a guess.
|
step.microcycle.operation = Microcycle::Address | Microcycle::ReadWrite | Microcycle::IsProgram; // IsProgram is a guess.
|
||||||
step.microcycle.address = &effective_address_;
|
step.microcycle.address = &effective_address_;
|
||||||
step.microcycle.value = isupper(access_pattern[1]) ? &program_counter_.halves.high : &program_counter_.halves.low;
|
step.microcycle.value = isupper(access_pattern[1]) ? &program_counter_.halves.high : &program_counter_.halves.low;
|
||||||
steps.push_back(step);
|
all_bus_steps_.push_back(step);
|
||||||
|
|
||||||
step.microcycle.length = HalfCycles(3);
|
step.microcycle.length = HalfCycles(3);
|
||||||
step.microcycle.operation |= Microcycle::LowerData | Microcycle::UpperData;
|
step.microcycle.operation |= Microcycle::LowerData | Microcycle::UpperData;
|
||||||
step.action = Step::Action::IncrementEffectiveAddress;
|
step.action = BusStep::Action::IncrementEffectiveAddress;
|
||||||
steps.push_back(step);
|
all_bus_steps_.push_back(step);
|
||||||
|
|
||||||
access_pattern += 2;
|
access_pattern += 2;
|
||||||
break;
|
break;
|
||||||
@ -92,13 +95,13 @@ std::vector<ProcessorStorage::Step> ProcessorStorage::assemble_program(const cha
|
|||||||
step.microcycle.operation = Microcycle::Address | Microcycle::ReadWrite | Microcycle::IsProgram;
|
step.microcycle.operation = Microcycle::Address | Microcycle::ReadWrite | Microcycle::IsProgram;
|
||||||
step.microcycle.address = &program_counter_.full;
|
step.microcycle.address = &program_counter_.full;
|
||||||
step.microcycle.value = &prefetch_queue_[1];
|
step.microcycle.value = &prefetch_queue_[1];
|
||||||
step.action = Step::Action::AdvancePrefetch;
|
step.action = BusStep::Action::AdvancePrefetch;
|
||||||
steps.push_back(step);
|
all_bus_steps_.push_back(step);
|
||||||
|
|
||||||
step.microcycle.length = HalfCycles(3);
|
step.microcycle.length = HalfCycles(3);
|
||||||
step.microcycle.operation |= Microcycle::LowerData | Microcycle::UpperData;
|
step.microcycle.operation |= Microcycle::LowerData | Microcycle::UpperData;
|
||||||
step.action = Step::Action::IncrementProgramCounter;
|
step.action = BusStep::Action::IncrementProgramCounter;
|
||||||
steps.push_back(step);
|
all_bus_steps_.push_back(step);
|
||||||
|
|
||||||
access_pattern += 2;
|
access_pattern += 2;
|
||||||
break;
|
break;
|
||||||
@ -112,11 +115,20 @@ std::vector<ProcessorStorage::Step> ProcessorStorage::assemble_program(const cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a final 'ScheduleNextProgram' sentinel.
|
// Add a final 'ScheduleNextProgram' sentinel.
|
||||||
Step end_program;
|
BusStep end_program;
|
||||||
end_program.action = Step::Action::ScheduleNextProgram;
|
end_program.action = BusStep::Action::ScheduleNextProgram;
|
||||||
steps.push_back(end_program);
|
all_bus_steps_.push_back(end_program);
|
||||||
|
|
||||||
return steps;
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessorStorage::BusStepCollection ProcessorStorage::assemble_standard_bus_steps() {
|
||||||
|
ProcessorStorage::BusStepCollection collection;
|
||||||
|
|
||||||
|
collection.four_step_Dn = assemble_program("np");
|
||||||
|
collection.six_step_Dn = assemble_program("np n");
|
||||||
|
|
||||||
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -131,81 +143,75 @@ std::vector<ProcessorStorage::Step> ProcessorStorage::assemble_program(const cha
|
|||||||
from known instructions to their disassembly rather than vice versa; especially
|
from known instructions to their disassembly rather than vice versa; especially
|
||||||
(iii) given that there are plentiful disassemblers against which to test work in progress.
|
(iii) given that there are plentiful disassemblers against which to test work in progress.
|
||||||
*/
|
*/
|
||||||
void ProcessorStorage::install_instruction(int instruction) {
|
void ProcessorStorage::install_instructions(const BusStepCollection &bus_step_collection) {
|
||||||
enum class Operation {
|
enum class Decoder {
|
||||||
ABCD, ADD, ADDA, ADDI, ADDQ, ADDX, AND, ANDI,
|
Decimal,
|
||||||
ASL, ASLrmw, ASR, ASRrmw, Bcc,
|
RegOpModeReg,
|
||||||
|
SizeModeRegisterImmediate,
|
||||||
TODO
|
DataSizeModeQuick
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PatternMapping {
|
struct PatternMapping {
|
||||||
uint16_t mask, value;
|
uint16_t mask, value;
|
||||||
Operation operation;
|
Operation operation;
|
||||||
|
Decoder decoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Credit here is due to 'wrm' (https://github.com/wrm-za I assume) for his public
|
Inspired partly by 'wrm' (https://github.com/wrm-za I assume); the following
|
||||||
domain 68000 disassembler, from which the table below was largely sourced.
|
table draws from the M68000 Programmer's Reference Manual, currently available at
|
||||||
Manual legwork has been extended to check this table against the M68000
|
|
||||||
Programmer's Reference Manual, currently available at
|
|
||||||
https://www.nxp.com/files-static/archives/doc/ref_manual/M68000PRM.pdf
|
https://www.nxp.com/files-static/archives/doc/ref_manual/M68000PRM.pdf
|
||||||
|
|
||||||
|
After each line is the internal page number on which documentation of that
|
||||||
|
instruction mapping can be found, followed by the page number within the PDF
|
||||||
|
linked above.
|
||||||
|
|
||||||
|
NB: a vector is used to allow easy iteration.
|
||||||
*/
|
*/
|
||||||
const std::vector<PatternMapping> mappings = {
|
const std::vector<PatternMapping> mappings = {
|
||||||
{0xf1f0, 0xc100, Operation::ABCD}, {0xf000, 0xd000, Operation::ADD},
|
{0xf1f0, 0x8100, Operation::SBCD, Decoder::Decimal}, // 4-171 (p275)
|
||||||
{0xf0c0, 0xd0c0, Operation::ADDA}, {0xff00, 0x0600, Operation::ADDI},
|
{0xf1f0, 0xc100, Operation::ABCD, Decoder::Decimal}, // 4-3 (p107)
|
||||||
{0xf100, 0x5000, Operation::ADDQ}, {0xf130, 0xd100, Operation::ADDX},
|
|
||||||
{0xf000, 0xc000, Operation::AND}, {0xff00, 0x0200, Operation::ANDI},
|
{0xf000, 0x8000, Operation::OR, Decoder::RegOpModeReg}, // 4-150 (p226)
|
||||||
{0xf118, 0xe100, Operation::ASL}, {0xffc0, 0xe1c0, Operation::ASLrmw},
|
{0xf000, 0x9000, Operation::SUB, Decoder::RegOpModeReg}, // 4-174 (p278)
|
||||||
{0xf118, 0xe000, Operation::ASR}, {0xffc0, 0xe0c0, Operation::ASRrmw},
|
{0xf000, 0xb000, Operation::EOR, Decoder::RegOpModeReg}, // 4-100 (p204)
|
||||||
{0xf000, 0x6000, Operation::Bcc}, {0xf1c0, 0x0140, Operation::TODO},
|
{0xf000, 0xc000, Operation::AND, Decoder::RegOpModeReg}, // 4-15 (p119)
|
||||||
{0xffc0, 0x0840, Operation::TODO}, {0xf1c0, 0x0180, Operation::TODO},
|
{0xf000, 0xd000, Operation::ADD, Decoder::RegOpModeReg}, // 4-4 (p108)
|
||||||
{0xffc0, 0x0880, Operation::TODO}, {0xf1c0, 0x01c0, Operation::TODO},
|
|
||||||
{0xffc0, 0x08c0, Operation::TODO}, {0xf1c0, 0x0100, Operation::TODO},
|
{0xff00, 0x0600, Operation::ADD, Decoder::SizeModeRegisterImmediate}, // 4-9 (p113)
|
||||||
{0xffc0, 0x0800, Operation::TODO}, {0xf1c0, 0x4180, Operation::TODO},
|
|
||||||
{0xff00, 0x4200, Operation::TODO}, {0xf100, 0xb000, Operation::TODO},
|
{0xff00, 0x0600, Operation::ADD, Decoder::DataSizeModeQuick}, // 4-11 (p115)
|
||||||
{0xf0c0, 0xb0c0, Operation::TODO}, {0xff00, 0x0c00, Operation::TODO},
|
|
||||||
{0xf138, 0xb108, Operation::TODO}, {0xf0f8, 0x50c8, Operation::TODO},
|
|
||||||
{0xf1c0, 0x81c0, Operation::TODO}, {0xf1c0, 0x80c0, Operation::TODO},
|
|
||||||
{0xf100, 0xb100, Operation::TODO}, {0xff00, 0x0a00, Operation::TODO},
|
|
||||||
{0xf100, 0xc100, Operation::TODO}, {0xffb8, 0x4880, Operation::TODO},
|
|
||||||
{0xffc0, 0x4ec0, Operation::TODO}, {0xffc0, 0x4e80, Operation::TODO},
|
|
||||||
{0xf1c0, 0x41c0, Operation::TODO}, {0xfff8, 0x4e50, Operation::TODO},
|
|
||||||
{0xf118, 0xe108, Operation::TODO}, {0xffc0, 0xe3c0, Operation::TODO},
|
|
||||||
{0xf118, 0xe008, Operation::TODO}, {0xffc0, 0xe2c0, Operation::TODO},
|
|
||||||
{0xc000, 0x0000, Operation::TODO}, {0xffc0, 0x44c0, Operation::TODO},
|
|
||||||
{0xffc0, 0x46c0, Operation::TODO}, {0xffc0, 0x40c0, Operation::TODO},
|
|
||||||
{0xfff0, 0x4e60, Operation::TODO}, {0xc1c0, 0x0040, Operation::TODO},
|
|
||||||
{0xfb80, 0x4880, Operation::TODO}, {0xf138, 0x0108, Operation::TODO},
|
|
||||||
{0xf100, 0x7000, Operation::TODO}, {0xf1c0, 0xc1c0, Operation::TODO},
|
|
||||||
{0xf1c0, 0xc0c0, Operation::TODO}, {0xffc0, 0x4800, Operation::TODO},
|
|
||||||
{0xff00, 0x4400, Operation::TODO}, {0xff00, 0x4000, Operation::TODO},
|
|
||||||
{0xffff, 0x4e71, Operation::TODO}, {0xff00, 0x4600, Operation::TODO},
|
|
||||||
{0xf000, 0x8000, Operation::TODO}, {0xff00, 0x0000, Operation::TODO},
|
|
||||||
{0xffc0, 0x4840, Operation::TODO}, {0xffff, 0x4e70, Operation::TODO},
|
|
||||||
{0xf118, 0xe118, Operation::TODO}, {0xffc0, 0xe7c0, Operation::TODO},
|
|
||||||
{0xf118, 0xe018, Operation::TODO}, {0xffc0, 0xe6c0, Operation::TODO},
|
|
||||||
{0xf118, 0xe110, Operation::TODO}, {0xffc0, 0xe5c0, Operation::TODO},
|
|
||||||
{0xf118, 0xe010, Operation::TODO}, {0xffc0, 0xe4c0, Operation::TODO},
|
|
||||||
{0xffff, 0x4e73, Operation::TODO}, {0xffff, 0x4e77, Operation::TODO},
|
|
||||||
{0xffff, 0x4e75, Operation::TODO}, {0xf1f0, 0x8100, Operation::TODO},
|
|
||||||
{0xf0c0, 0x50c0, Operation::TODO}, {0xffff, 0x4e72, Operation::TODO},
|
|
||||||
{0xf000, 0x9000, Operation::TODO}, {0xf0c0, 0x90c0, Operation::TODO},
|
|
||||||
{0xff00, 0x0400, Operation::TODO}, {0xf100, 0x5100, Operation::TODO},
|
|
||||||
{0xf130, 0x9100, Operation::TODO}, {0xfff8, 0x4840, Operation::TODO},
|
|
||||||
{0xffc0, 0x4ac0, Operation::TODO}, {0xfff0, 0x4e40, Operation::TODO},
|
|
||||||
{0xffff, 0x4e76, Operation::TODO}, {0xff00, 0x4a00, Operation::TODO},
|
|
||||||
{0xfff8, 0x4e58, Operation::TODO}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Perform a linear search of the mappings above for this instruction.
|
// Perform a linear search of the mappings above for this instruction.
|
||||||
for(const auto &mapping: mappings) {
|
for(int instruction = 0; instruction < 65536; ++instruction) {
|
||||||
if((instruction & mapping.mask) == mapping.value) {
|
for(const auto &mapping: mappings) {
|
||||||
if(mapping.operation == Operation::TODO) {
|
if((instruction & mapping.mask) == mapping.value) {
|
||||||
std::cout << std::hex << std::setw(4) << std::setfill('0');
|
switch(mapping.decoder) {
|
||||||
std::cout << "Yet to implement, instruction matching: x & " << mapping.mask << " == " << mapping.value << std::endl;
|
case Decoder::Decimal: {
|
||||||
|
const int destination = (instruction >> 8) & 7;
|
||||||
|
const int source = instruction & 7;
|
||||||
|
if(instruction & 8) {
|
||||||
|
std::cout << "Address to address (both predecrement) from " << source << " to " << destination << std::endl;
|
||||||
|
} else {
|
||||||
|
instructions[instruction].operation = mapping.operation;
|
||||||
|
instructions[instruction].source = &data_[source];
|
||||||
|
instructions[instruction].destination = &data_[destination];
|
||||||
|
// instructions[instruction].destination.micro_operations =
|
||||||
|
std::cout << "Data register to data register from " << source << " to " << destination << std::endl;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Decoder::RegOpModeReg: {
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
std::cerr << "Unhandled decoder " << int(mapping.decoder) << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,15 @@ class ProcessorStorage {
|
|||||||
uint32_t effective_address_;
|
uint32_t effective_address_;
|
||||||
RegisterPair32 bus_data_;
|
RegisterPair32 bus_data_;
|
||||||
|
|
||||||
|
enum class Operation {
|
||||||
|
ABCD, SBCD,
|
||||||
|
ADD, AND, EOR, OR, SUB,
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
A step is a microcycle to perform plus an action to occur afterwards, if any.
|
Bus steps are sequences of things to communicate to the bus.
|
||||||
*/
|
*/
|
||||||
struct Step {
|
struct BusStep {
|
||||||
Microcycle microcycle;
|
Microcycle microcycle;
|
||||||
enum class Action {
|
enum class Action {
|
||||||
None,
|
None,
|
||||||
@ -56,15 +61,53 @@ class ProcessorStorage {
|
|||||||
} action = Action::None;
|
} action = Action::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Special programs.
|
/*!
|
||||||
std::vector<Step> reset_program_;
|
A micro-op is: (i) an action to take; and (ii) a sequence of bus operations
|
||||||
|
to perform after taking the action.
|
||||||
|
|
||||||
// Current program pointer.
|
A nullptr bus_program terminates a sequence of micro operations.
|
||||||
Step *active_program_ = nullptr;
|
*/
|
||||||
|
struct MicroOp {
|
||||||
|
enum class Action {
|
||||||
|
None,
|
||||||
|
PerformOperation
|
||||||
|
} action = Action::None;
|
||||||
|
BusStep *bus_program = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A program represents the implementation of a particular opcode, as a sequence
|
||||||
|
of micro-ops and, separately, the operation to perform plus whatever other
|
||||||
|
fields the operation requires.
|
||||||
|
*/
|
||||||
|
struct Program {
|
||||||
|
MicroOp *micro_operations = nullptr;
|
||||||
|
Operation operation;
|
||||||
|
RegisterPair32 *source;
|
||||||
|
RegisterPair32 *destination;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Storage for all the sequences of bus steps and micro-ops used throughout
|
||||||
|
// the 68000.
|
||||||
|
std::vector<BusStep> all_bus_steps_;
|
||||||
|
std::vector<MicroOp> all_micro_ops_;
|
||||||
|
|
||||||
|
// A lookup table from instructions to implementations.
|
||||||
|
Program instructions[65536];
|
||||||
|
|
||||||
|
// Special programs, for exception handlers.
|
||||||
|
BusStep *reset_program_;
|
||||||
|
|
||||||
|
// Current bus step pointer, and outer program pointer.
|
||||||
|
Program *active_program_ = nullptr;
|
||||||
|
MicroOp *active_micro_op_ = nullptr;
|
||||||
|
BusStep *active_step_ = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*!
|
/*!
|
||||||
Produces a vector of Steps that implement the described program.
|
Installs BusSteps that implement the described program into the relevant
|
||||||
|
instance storage, returning the offset within @c all_bus_steps_ at which
|
||||||
|
the generated steps begin.
|
||||||
|
|
||||||
@param access_pattern A string describing the bus activity that occurs
|
@param access_pattern A string describing the bus activity that occurs
|
||||||
during this program. This should follow the same general pattern as
|
during this program. This should follow the same general pattern as
|
||||||
@ -103,13 +146,19 @@ class ProcessorStorage {
|
|||||||
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.
|
||||||
*/
|
*/
|
||||||
std::vector<Step> assemble_program(const char *access_pattern);
|
size_t assemble_program(const char *access_pattern);
|
||||||
|
|
||||||
|
struct BusStepCollection {
|
||||||
|
size_t six_step_Dn;
|
||||||
|
size_t four_step_Dn;
|
||||||
|
};
|
||||||
|
BusStepCollection assemble_standard_bus_steps();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Disassembles the instruction @c instruction and inserts it into the
|
Disassembles the instruction @c instruction and inserts it into the
|
||||||
appropriate lookup tables.
|
appropriate lookup tables.
|
||||||
*/
|
*/
|
||||||
void install_instruction(int instruction);
|
void install_instructions(const BusStepCollection &);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MC68000Storage_h */
|
#endif /* MC68000Storage_h */
|
||||||
|
Loading…
Reference in New Issue
Block a user