mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-23 03:32:32 +00:00
Adds BRA and Bcc.
This commit is contained in:
parent
7163b1132c
commit
be4b38c76a
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user