1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-25 18:30:21 +00:00

Adds BRA and Bcc.

This commit is contained in:
Thomas Harte 2019-03-25 22:54:49 -04:00
parent 7163b1132c
commit be4b38c76a
3 changed files with 107 additions and 10 deletions

View File

@ -90,6 +90,73 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
active_program_->destination->halves.low.halves.low = uint8_t(result);
} break;
// BRA: alters the program counter, exclusively via the prefetch queue.
case Operation::BRA: {
const int8_t byte_offset = int8_t(prefetch_queue_.halves.high.halves.low);
// A non-zero offset byte branches by just that amount; otherwise use the word
// after as an offset. In both cases, treat as signed.
if(byte_offset) {
program_counter_.full = (program_counter_.full + byte_offset) - 2;
} else {
program_counter_.full += int16_t(prefetch_queue_.halves.low.full);
}
} break;
// Bcc: evaluates the relevant condition and displacement size and then:
// if condition is false, schedules bus operations to get past this instruction;
// otherwise applies the offset and schedules bus operations to refill the prefetch queue.
case Operation::Bcc: {
// Grab the 8-bit offset.
const int8_t byte_offset = int8_t(prefetch_queue_.halves.high.halves.low);
// Test the conditional.
bool should_branch;
switch(prefetch_queue_.halves.high.halves.high & 0xf) {
default:
case 0x00: should_branch = true; break; // true
case 0x01: should_branch = false; break; // false
case 0x02: should_branch = zero_result_ && !carry_flag_; break; // high
case 0x03: should_branch = !zero_result_ || carry_flag_; break; // low or same
case 0x04: should_branch = !carry_flag_; break; // carry clear
case 0x05: should_branch = carry_flag_; break; // carry set
case 0x06: should_branch = zero_result_; break; // not equal
case 0x07: should_branch = !zero_result_; break; // equal
case 0x08: should_branch = !overflow_flag_; break; // overflow clear
case 0x09: should_branch = overflow_flag_; break; // overflow set
case 0x0a: should_branch = !negative_flag_; break; // positive
case 0x0b: should_branch = negative_flag_; break; // negative
case 0x0c:
should_branch = (negative_flag_ && overflow_flag_) || (!negative_flag_ && !overflow_flag_);
break; // greater than or equal
case 0x0d:
should_branch = (negative_flag_ || !overflow_flag_) && (!negative_flag_ || overflow_flag_);
break; // less than
case 0x0e:
should_branch = zero_result_ && ((negative_flag_ && overflow_flag_) || (!negative_flag_ && !overflow_flag_));
break; // greater than
case 0x0f:
should_branch = (!zero_result_ || negative_flag_) && (!overflow_flag_ || !negative_flag_) && overflow_flag_;
break; // less than or equal
}
// Schedule something appropriate, by rewriting the program for this instruction temporarily.
if(should_branch) {
if(byte_offset) {
program_counter_.full = (program_counter_.full + byte_offset) - 2; // - 2 because this should be calculated from the high word of the prefetch.
} else {
program_counter_.full += int16_t(prefetch_queue_.halves.low.full);
}
active_micro_op_->bus_program = branch_taken_bus_steps_;
} else {
if(byte_offset) {
active_micro_op_->bus_program = branch_byte_not_taken_bus_steps_;
} else {
active_micro_op_->bus_program = branch_word_not_taken_bus_steps_;
}
}
} break;
/*
CMP.b, CMP.l and CMP.w: sets the condition flags (other than extend) based on a subtraction
of the source from the destination; the result of the subtraction is not stored.

View File

@ -238,6 +238,8 @@ struct ProcessorStorageConstructor {
MOVEtoSR, // six lowest bits are [mode, register], decoding to MOVE SR
CMPI, // eight lowest bits are [size, mode, register], decoding to CMPI
BRA, // eight lowest bits are ignored, and an 'n np np' is scheduled
Bcc, // twelve lowest bits are ignored, only a PerformAction is scheduled
};
using Operation = ProcessorStorage::Operation;
@ -280,9 +282,12 @@ struct ProcessorStorageConstructor {
{0xffc0, 0x46c0, Operation::MOVEtoSR, Decoder::MOVEtoSR}, // 6-19 (p473)
{0xffc0, 0x0c00, Operation::CMPb, Decoder::CMPI},
{0xffc0, 0x0c40, Operation::CMPw, Decoder::CMPI},
{0xffc0, 0x0c80, Operation::CMPl, Decoder::CMPI},
{0xffc0, 0x0c00, Operation::CMPb, Decoder::CMPI}, // 4-79 (p183)
{0xffc0, 0x0c40, Operation::CMPw, Decoder::CMPI}, // 4-79 (p183)
{0xffc0, 0x0c80, Operation::CMPl, Decoder::CMPI}, // 4-79 (p183)
{0xff00, 0x6000, Operation::BRA, Decoder::BRA}, // 4-55 (p159)
{0xf000, 0x6000, Operation::Bcc, Decoder::Bcc}, // 4-25 (p129)
};
std::vector<size_t> micro_op_pointers(65536, std::numeric_limits<size_t>::max());
@ -307,6 +312,18 @@ struct ProcessorStorageConstructor {
const int source_mode = (instruction >> 3) & 7;
switch(mapping.decoder) {
// This decoder actually decodes nothing; it just schedules a PerformOperation followed by an empty step.
case Decoder::Bcc: {
op(Action::PerformOperation);
op();
} break;
// A little artificial, there's nothing really to decode for BRA.
case Decoder::BRA: {
op(Action::PerformOperation, seq("n np np"));
op();
} break;
// Decodes the format used by ABCD and SBCD.
case Decoder::Decimal: {
const int destination = (instruction >> 9) & 7;
@ -944,17 +961,23 @@ struct ProcessorStorageConstructor {
CPU::MC68000::ProcessorStorage::ProcessorStorage() {
ProcessorStorageConstructor constructor(*this);
// Create the exception programs.
// Create the special programs.
const size_t reset_offset = constructor.assemble_program("n n n n n nn nF nf nV nv np np");
const size_t branch_taken_offset = constructor.assemble_program("n np np");
const size_t branch_byte_not_taken_offset = constructor.assemble_program("nn np");
const size_t branch_word_not_taken_offset = constructor.assemble_program("nn np np");
// Install operations.
constructor.install_instructions();
// Realise the exception programs as direct pointers.
reset_program_ = &all_bus_steps_[reset_offset];
// Realise the special programs as direct pointers.
reset_bus_steps_ = &all_bus_steps_[reset_offset];
branch_taken_bus_steps_ = &all_bus_steps_[branch_taken_offset];
branch_byte_not_taken_bus_steps_ = &all_bus_steps_[branch_byte_not_taken_offset];
branch_word_not_taken_bus_steps_ = &all_bus_steps_[branch_word_not_taken_offset];
// Set initial state. Largely TODO.
active_step_ = reset_program_;
active_step_ = reset_bus_steps_;
effective_address_[0] = 0;
is_supervisor_ = 1;
}

View File

@ -50,7 +50,9 @@ class ProcessorStorage {
MOVEtoSR, MOVEfromSR,
CMPb, CMPw, CMPl
CMPb, CMPw, CMPl,
BRA, Bcc
};
/*!
@ -232,8 +234,13 @@ class ProcessorStorage {
// A lookup table from instructions to implementations.
Program instructions[65536];
// Special programs, for exception handlers.
BusStep *reset_program_;
// Special steps for exception handlers.
BusStep *reset_bus_steps_;
// Special micro-op sequences for conditionals.
BusStep *branch_taken_bus_steps_;
BusStep *branch_byte_not_taken_bus_steps_;
BusStep *branch_word_not_taken_bus_steps_;
// Current bus step pointer, and outer program pointer.
Program *active_program_ = nullptr;