1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-03 11:30:02 +00:00

Implements MOVE to SR, fleshing out the final bits of storage for the status word.

This commit is contained in:
Thomas Harte 2019-03-24 18:20:54 -04:00
parent 47359dc8f1
commit 3ccec1c996
3 changed files with 196 additions and 47 deletions

View File

@ -6,6 +6,28 @@
// Copyright © 2019 Thomas Harte. All rights reserved.
//
#define get_status() \
( \
(carry_flag_ ? 0x0001 : 0x0000) | \
(overflow_flag_ ? 0x0002 : 0x0000) | \
(zero_result_ ? 0x0000 : 0x0004) | \
(negative_flag_ ? 0x0008 : 0x0000) | \
(extend_flag_ ? 0x0010 : 0x0000) | \
(interrupt_level_ << 8) | \
(trace_flag_ ? 0x8000 : 0x0000) | \
(is_supervisor_ << 13) \
)
#define set_status(x) \
carry_flag_ = (x) & 0x0001; \
overflow_flag_ = (x) & 0x0002; \
zero_result_ = ((x) & 0x0004) ^ 0x0004; \
negative_flag_ = (x) & 0x0008; \
extend_flag_ = (x) & 0x0010; \
interrupt_level_ = ((x) >> 8) & 7; \
trace_flag_ = (x) & 0x8000; \
is_supervisor_ = ((x) >> 13) & 1;
template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>::run_for(HalfCycles duration) {
HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
while(remaining_duration > HalfCycles(0)) {
@ -55,7 +77,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
if(result > 0x99) result += 0x60;
// Set all flags essentially as if this were normal addition.
zero_flag_ |= result & 0xff;
zero_result_ |= result & 0xff;
extend_flag_ = carry_flag_ = result & ~0xff;
negative_flag_ = result & 0x80;
overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80;
@ -76,7 +98,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
if(result > 0x99) result -= 0x60;
// Set all flags essentially as if this were normal subtraction.
zero_flag_ |= result & 0xff;
zero_result_ |= result & 0xff;
extend_flag_ = carry_flag_ = result & ~0xff;
negative_flag_ = result & 0x80;
overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80;
@ -90,20 +112,20 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
and set negative, zero, overflow and carry as appropriate.
*/
case Operation::MOVEb:
zero_flag_ = active_program_->destination->halves.low.halves.low = active_program_->source->halves.low.halves.low;
negative_flag_ = zero_flag_ & 0x80;
zero_result_ = active_program_->destination->halves.low.halves.low = active_program_->source->halves.low.halves.low;
negative_flag_ = zero_result_ & 0x80;
overflow_flag_ = carry_flag_ = 0;
break;
case Operation::MOVEw:
zero_flag_ = active_program_->destination->halves.low.full = active_program_->source->halves.low.full;
negative_flag_ = zero_flag_ & 0x8000;
zero_result_ = active_program_->destination->halves.low.full = active_program_->source->halves.low.full;
negative_flag_ = zero_result_ & 0x8000;
overflow_flag_ = carry_flag_ = 0;
break;
case Operation::MOVEl:
zero_flag_ = active_program_->destination->full = active_program_->source->full;
negative_flag_ = zero_flag_ & 0x80000000;
zero_result_ = active_program_->destination->full = active_program_->source->full;
negative_flag_ = zero_result_ & 0x80000000;
overflow_flag_ = carry_flag_ = 0;
break;
@ -122,6 +144,21 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
active_program_->destination->full = active_program_->source->full;
break;
/*
Status word moves.
*/
case Operation::MOVEtoSR:
set_status(active_program_->source->full);
break;
case Operation::MOVEfromSR:
active_program_->source->halves.low.full = get_status();
break;
/*
Development period debugging.
*/
default:
std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl;
break;
@ -129,20 +166,20 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
break;
case int(MicroOp::Action::SetMoveFlagsb):
zero_flag_ = active_program_->source->halves.low.halves.low;
negative_flag_ = zero_flag_ & 0x80;
zero_result_ = active_program_->source->halves.low.halves.low;
negative_flag_ = zero_result_ & 0x80;
overflow_flag_ = carry_flag_ = 0;
break;
case int(MicroOp::Action::SetMoveFlagsw):
zero_flag_ = active_program_->source->halves.low.full;
negative_flag_ = zero_flag_ & 0x8000;
zero_result_ = active_program_->source->halves.low.full;
negative_flag_ = zero_result_ & 0x8000;
overflow_flag_ = carry_flag_ = 0;
break;
case int(MicroOp::Action::SetMoveFlagsl):
zero_flag_ = active_program_->source->full;
negative_flag_ = zero_flag_ & 0x80000000;
zero_result_ = active_program_->source->full;
negative_flag_ = zero_result_ & 0x80000000;
overflow_flag_ = carry_flag_ = 0;
break;
@ -322,15 +359,7 @@ template <class T, bool dtack_is_implicit> ProcessorState Processor<T, dtack_is_
state.user_stack_pointer = stack_pointers_[0].full;
state.supervisor_stack_pointer = stack_pointers_[1].full;
// TODO: rest of status word: interrupt level, trace flag.
state.status =
(carry_flag_ ? 0x0001 : 0x0000) |
(overflow_flag_ ? 0x0002 : 0x0000) |
(zero_flag_ ? 0x0000 : 0x0004) |
(negative_flag_ ? 0x0008 : 0x0000) |
(extend_flag_ ? 0x0010 : 0x0000) |
(is_supervisor_ << 13);
state.status = get_status();
return state;
}
@ -341,14 +370,10 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
stack_pointers_[0].full = state.user_stack_pointer;
stack_pointers_[1].full = state.supervisor_stack_pointer;
carry_flag_ = state.status & 0x0001;
overflow_flag_ = state.status & 0x0002;
zero_flag_ = (state.status & 0x0004) ^ 0x0004;
negative_flag_ = state.status & 0x0008;
extend_flag_ = state.status & 0x0010;
set_status(state.status);
is_supervisor_ = (state.status >> 13) & 1;
address_[7] = stack_pointers_[is_supervisor_];
// TODO: rest of status word: interrupt level, trace flag.
}
#undef get_status
#undef set_status

View File

@ -18,6 +18,17 @@ struct ProcessorStorageConstructor {
using BusStep = ProcessorStorage::BusStep;
int calc_action_for_mode(int mode) const {
using Action = ProcessorBase::MicroOp::Action;
switch(mode & 0xff) {
default: return 0;
case 0x12: return int(Action::CalcD16PC); // (d16, PC)
case 0x13: return int(Action::CalcD8PCXn); // (d8, PC, Xn)
case 0x05: return int(Action::CalcD16An); // (d16, An)
case 0x06: return int(Action::CalcD8AnXn); // (d8, An, Xn)
}
}
/*!
Installs BusSteps that implement the described program into the relevant
instance storage, returning the offset within @c all_bus_steps_ at which
@ -163,8 +174,10 @@ struct ProcessorStorageConstructor {
}
steps.push_back(step);
++address_iterator;
if(!isupper(access_pattern[1])) ++(*scratch_data);
if(!isupper(access_pattern[1])) {
++(*scratch_data);
++address_iterator;
}
access_pattern += 2;
} break;
}
@ -214,7 +227,9 @@ struct ProcessorStorageConstructor {
RegOpModeReg,
SizeModeRegisterImmediate,
DataSizeModeQuick,
RegisterModeModeRegister
RegisterModeModeRegister, // i.e. twelve lowest bits are register, mode, mode, register, for destination and source respectively.
ModeRegister, // i.e. six lowest bits are mode, then register.
MOVEtoSR
};
using Operation = ProcessorStorage::Operation;
@ -254,6 +269,8 @@ struct ProcessorStorageConstructor {
{0xf000, 0x1000, Operation::MOVEb, Decoder::RegisterModeModeRegister}, // 4-116 (p220)
{0xf000, 0x2000, Operation::MOVEl, Decoder::RegisterModeModeRegister}, // 4-116 (p220)
{0xf000, 0x3000, Operation::MOVEw, Decoder::RegisterModeModeRegister}, // 4-116 (p220)
{0xffc0, 0x46c0, Operation::MOVEtoSR, Decoder::MOVEtoSR}, // 6-19 (p473)
};
std::vector<size_t> micro_op_pointers(65536, std::numeric_limits<size_t>::max());
@ -295,7 +312,82 @@ struct ProcessorStorageConstructor {
}
} break;
// Decodes the format used by all the MOVEs.
case Decoder::MOVEtoSR: {
const int source_register = instruction & 7;
const int source_mode = (instruction >> 3) & 7;
switch(source_mode) {
case 0: // Dn
storage_.instructions[instruction].source = &storage_.data_[source_register];
break;
case 1: continue; // An
default: // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L
storage_.instructions[instruction].source = &storage_.bus_data_[0];
storage_.instructions[instruction].destination = &storage_.bus_data_[1];
break;
}
/* DEVIATION FROM YACHT.TXT: it has all of these reading an extra word from the PC;
this looks like a mistake so I've padded with nil cycles in the middle. */
switch( (source_mode == 7) ? (0x10 | source_register) : source_mode) {
case 0x00: // MOVE Dn, SR
op(Action::PerformOperation, seq("nn np"));
op();
break;
case 0x02: // MOVE (An), SR
case 0x03: // MOVE (An)+, SR
op(Action::None, seq("nr nn nn np", { &storage_.address_[source_register].full }));
if(source_mode == 0x3) {
op(int(Action::Increment2) | MicroOp::SourceMask);
}
op(Action::PerformOperation);
break;
case 0x04: // MOVE -(An), SR
op(Action::Decrement2, seq("n nr nn nn np", { &storage_.address_[source_register].full }));
op(Action::PerformOperation);
break;
#define pseq(x) ((source_mode == 0x06) || (source_mode == 0x13) ? "n" x : x)
case 0x12: // MOVE (d16, PC), SR
case 0x13: // MOVE (d8, PC, Xn), SR
case 0x05: // MOVE (d16, An), SR
case 0x06: // MOVE (d8, An, Xn), SR
op(calc_action_for_mode(source_mode) | MicroOp::SourceMask, seq(pseq("np nr nn nn np"), { &storage_.effective_address_[0] }));
op(Action::PerformOperation);
break;
#undef pseq
case 0x10: // MOVE (xxx).W, SR
op(
int(MicroOp::Action::AssembleWordFromPrefetch) | MicroOp::SourceMask,
seq("np nr nn nn np", { &storage_.effective_address_[0] }));
op(Action::PerformOperation);
break;
case 0x11: // MOVE (xxx).L, SR
op(Action::None, seq("np"));
op(int(MicroOp::Action::AssembleLongWordFromPrefetch) | MicroOp::SourceMask, seq("np nr", { &storage_.effective_address_[0] }));
op(Action::PerformOperation, seq("nn nn np"));
op();
break;
case 0x14: // MOVE #, SR
storage_.instructions[instruction].source = &storage_.prefetch_queue_;
op(int(Action::PerformOperation), seq("np nn nn np"));
op();
break;
default: continue;
}
} break;
// Decodes the format used by most MOVEs and all MOVEAs.
case Decoder::RegisterModeModeRegister: {
const int source_register = instruction & 7;
const int source_mode = (instruction >> 3) & 7;
@ -445,18 +537,44 @@ struct ProcessorStorageConstructor {
operation = Operation::MOVEAl;
case 0x10200: // MOVE.l (An), Dn
case 0x10300: // MOVE.l (An)+, Dn
op(Action::CopySourceToEffectiveAddress, seq("nR nr np", {&storage_.effective_address_[0], &storage_.effective_address_[0]}));
op(Action::CopySourceToEffectiveAddress, seq("nR nr np", { &storage_.effective_address_[0] }));
if(source_mode == 0x3) {
op(int(Action::Increment4) | MicroOp::SourceMask);
}
op(Action::PerformOperation);
break;
case 0x0202: // MOVE (An), (An)
case 0x0302: // MOVE (An)+, (An)
case 0x0203: // MOVE (An), (An)+
case 0x0303: // MOVE (An)+, (An)+
// nr nw np
case 0x00202: // MOVE.bw (An), (An)
case 0x00302: // MOVE.bw (An)+, (An)
case 0x00203: // MOVE.bw (An), (An)+
case 0x00303: // MOVE.bw (An)+, (An)+
op(Action::None, seq("nr", { &storage_.address_[source_register].full }));
op(Action::PerformOperation, seq("nw np", { &storage_.address_[destination_register].full }));
if(source_mode == 0x3 || destination_mode == 0x3) {
op(
int(is_byte_access ? Action::Increment1 : Action::Increment2) |
(source_mode == 0x3 ? MicroOp::SourceMask : 0) |
(source_mode == 0x3 ? MicroOp::DestinationMask : 0));
} else {
op();
}
continue;
case 0x10202: // MOVE.l (An), (An)
case 0x10302: // MOVE.l (An)+, (An)
case 0x10203: // MOVE.l (An), (An)+
case 0x10303: // MOVE.l (An)+, (An)+
op(Action::CopyDestinationToEffectiveAddress);
op(Action::CopySourceToEffectiveAddress, seq("nR nr", { &storage_.effective_address_[0] }));
op(Action::PerformOperation, seq("nW nw np", { &storage_.effective_address_[1] }));
if(source_mode == 0x3 || destination_mode == 0x3) {
op(
int(Action::Increment4) |
(source_mode == 0x3 ? MicroOp::SourceMask : 0) |
(source_mode == 0x3 ? MicroOp::DestinationMask : 0));
} else {
op();
}
continue;
case 0x0204: // MOVE (An), -(An)
@ -620,11 +738,12 @@ struct ProcessorStorageConstructor {
// Source = (xxx).L
//
case 0x1101: // MOVEA (xxx).W, Dn
case 0x1101: // MOVEA (xxx).L, Dn
operation = Operation::MOVEAw;
case 0x1100: // MOVE (xxx).W, Dn
op(int(MicroOp::Action::AssembleWordFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(Action::PerformOperation, seq("nr np", { &storage_.effective_address_[0] }, !is_byte_access));
case 0x1100: // MOVE (xxx).L, Dn
op(Action::None, seq("np"));
op(int(MicroOp::Action::AssembleLongWordFromPrefetch) | MicroOp::SourceMask, seq("np nr", { &storage_.effective_address_[0] }, !is_byte_access));
op(Action::PerformOperation, seq("np"));
op();
break;

View File

@ -26,11 +26,13 @@ class ProcessorStorage {
// Various status bits.
int is_supervisor_;
uint_fast32_t zero_flag_; // The zero flag is set if this value is zero.
int interrupt_level_;
uint_fast32_t zero_result_; // The zero flag is set if this value is zero.
uint_fast32_t carry_flag_; // The carry flag is set if this value is non-zero.
uint_fast32_t extend_flag_; // The extend flag is set if this value is non-zero.
uint_fast32_t overflow_flag_; // The overflow flag is set if this value is non-zero.
uint_fast32_t negative_flag_; // The negative flag is set if this value is non-zero.
uint_fast32_t trace_flag_; // The trace flag is set if this value is non-zero.
// Generic sources and targets for memory operations;
// by convention: [0] = source, [1] = destination.
@ -44,7 +46,9 @@ class ProcessorStorage {
ADD, AND, EOR, OR, SUB,
MOVEb, MOVEw, MOVEl,
MOVEAw, MOVEAl
MOVEAw, MOVEAl,
MOVEtoSR, MOVEfromSR
};
/*!
@ -192,6 +196,7 @@ class ProcessorStorage {
RegisterPair32 *source = nullptr;
RegisterPair32 *destination = nullptr;
Operation operation;
bool requires_supervisor = false;
};
// Storage for all the sequences of bus steps and micro-ops used throughout