mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-19 08:31:11 +00:00
Decision: operation is not a template parameter. Hence can use condition as fully typed.
This commit is contained in:
parent
a86c5ccdc9
commit
52f355db24
@ -28,41 +28,24 @@ namespace M68k {
|
||||
|
||||
// TODO: decisions outstanding:
|
||||
//
|
||||
// (1) for DBcc, etc, should this receive the opcode in order to decode the conditional,
|
||||
// or is it a design error to do any _decoding_ here rather than in the decoder? If
|
||||
// the latter, should the internal cc operations all treat conditional as another
|
||||
// Q-style operand?
|
||||
//
|
||||
// (2) should I reintroduce the BTSTl/BTSTw-type distinctions, given that the only way to
|
||||
// (1) should I reintroduce the BTSTl/BTSTw-type distinctions, given that the only way to
|
||||
// determine them otherwise is by operand types and I'm hoping to treat data into
|
||||
// here as a black box?
|
||||
//
|
||||
// (3) to what extent, if any, should this function have responsibility for a MOVEM, MOVEP,
|
||||
// (2) to what extent, if any, should this function have responsibility for a MOVEM, MOVEP,
|
||||
// etc? This factoring is inteded to separate the bus interface from internal logic so
|
||||
// is there much to do here in any case? As currently drafted, something else will
|
||||
// already have had to check the operation and cue up data.
|
||||
//
|
||||
// (4) related to that, should the flow controller actually offer effective address calculation
|
||||
// and load/stores, along with a flag indicating whether to stop after loads? By the
|
||||
// magic of templates that'd avoid having a correlated sequencer — for the non-bus-accurate
|
||||
// 68ks the loads and stores could be performed immediately, for the accurate they could
|
||||
// be enqueued, then performed, then a second call to perform that now has the data loaded
|
||||
// could be performed.
|
||||
//
|
||||
// (5) is it really helpful for operation to be a template parameter? I'm trying to avoid forcing
|
||||
// an additional `switch` if it's likely that the caller has already applied one, but does
|
||||
// that objective justify the syntax overhead for callers that don't inherently have their
|
||||
// own `switch`? Do the first sort of callers really exist?
|
||||
|
||||
template <
|
||||
Operation operation,
|
||||
Model model,
|
||||
typename FlowController
|
||||
> void perform(CPU::SlicedInt32 &src, CPU::SlicedInt32 &dest, Status &status, FlowController &flow_controller) {
|
||||
> void perform(Preinstruction instruction, CPU::SlicedInt32 &src, CPU::SlicedInt32 &dest, Status &status, FlowController &flow_controller) {
|
||||
|
||||
#define sub_overflow() ((result ^ destination) & (destination ^ source))
|
||||
#define add_overflow() ((result ^ destination) & ~(destination ^ source))
|
||||
switch(operation) {
|
||||
switch(instruction.operation) {
|
||||
/*
|
||||
ABCD adds the lowest bytes from the source and destination using BCD arithmetic,
|
||||
obeying the extend flag.
|
||||
@ -298,7 +281,7 @@ template <
|
||||
case Operation::Bccw:
|
||||
case Operation::Bccl: {
|
||||
// Test the conditional, treating 'false' as true.
|
||||
const bool should_branch = status.evaluate_condition(flow_controller.decode_conditional());
|
||||
const bool should_branch = status.evaluate_condition(instruction.condition());
|
||||
|
||||
// Schedule something appropriate, by rewriting the program for this instruction temporarily.
|
||||
if(should_branch) {
|
||||
@ -310,7 +293,7 @@ template <
|
||||
|
||||
case Operation::DBcc:
|
||||
// Decide what sort of DBcc this is.
|
||||
if(!status.evaluate_condition(flow_controller.decode_conditional())) {
|
||||
if(!status.evaluate_condition(instruction.condition())) {
|
||||
-- src.w;
|
||||
|
||||
if(src.w == 0xffff) {
|
||||
@ -327,7 +310,7 @@ template <
|
||||
break;
|
||||
|
||||
case Operation::Scc:
|
||||
dest.b = status.evaluate_condition(src.l) ? 0xff : 0x00;
|
||||
dest.b = status.evaluate_condition(instruction.condition()) ? 0xff : 0x00;
|
||||
break;
|
||||
|
||||
/*
|
||||
|
@ -27,10 +27,9 @@ struct NullFlowController {
|
||||
/// branch, or consumes additional cycles due to the particular value of the operands (on the 68000, think DIV or MUL),
|
||||
/// that'll be notified to the @c flow_controller.
|
||||
template <
|
||||
Operation op,
|
||||
Model model,
|
||||
typename FlowController
|
||||
> void perform(CPU::RegisterPair32 &source, CPU::RegisterPair32 &dest, Status &status, FlowController &flow_controller);
|
||||
> void perform(Preinstruction instruction, CPU::RegisterPair32 &source, CPU::RegisterPair32 &dest, Status &status, FlowController &flow_controller);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
#ifndef InstructionSets_M68k_Status_h
|
||||
#define InstructionSets_M68k_Status_h
|
||||
|
||||
#include "Instruction.hpp"
|
||||
|
||||
namespace InstructionSet {
|
||||
namespace M68k {
|
||||
|
||||
@ -70,29 +72,29 @@ struct Status {
|
||||
return is_supervisor_;
|
||||
}
|
||||
|
||||
/// Evaluates the condition described in the low four bits of @c code
|
||||
template <typename IntT> bool evaluate_condition(IntT code) {
|
||||
switch(code & 0xf) {
|
||||
/// Evaluates @c condition.
|
||||
bool evaluate_condition(Condition condition) {
|
||||
switch(condition) {
|
||||
default:
|
||||
case 0x00: return true; // true
|
||||
case 0x01: return false; // false
|
||||
case 0x02: return zero_result_ && !carry_flag_; // high
|
||||
case 0x03: return !zero_result_ || carry_flag_; // low or same
|
||||
case 0x04: return !carry_flag_; // carry clear
|
||||
case 0x05: return carry_flag_; // carry set
|
||||
case 0x06: return zero_result_; // not equal
|
||||
case 0x07: return !zero_result_; // equal
|
||||
case 0x08: return !overflow_flag_; // overflow clear
|
||||
case 0x09: return overflow_flag_; // overflow set
|
||||
case 0x0a: return !negative_flag_; // positive
|
||||
case 0x0b: return negative_flag_; // negative
|
||||
case 0x0c: // greater than or equal
|
||||
case Condition::True: return true;
|
||||
case Condition::False: return false;
|
||||
case Condition::High: return zero_result_ && !carry_flag_;
|
||||
case Condition::LowOrSame: return !zero_result_ || carry_flag_;
|
||||
case Condition::CarryClear: return !carry_flag_;
|
||||
case Condition::CarrySet: return carry_flag_;
|
||||
case Condition::NotEqual: return zero_result_;
|
||||
case Condition::Equal: return !zero_result_;
|
||||
case Condition::OverflowClear: return !overflow_flag_;
|
||||
case Condition::OverflowSet: return overflow_flag_;
|
||||
case Condition::Positive: return !negative_flag_;
|
||||
case Condition::Negative: return negative_flag_;
|
||||
case Condition::GreaterThanOrEqual:
|
||||
return (negative_flag_ && overflow_flag_) || (!negative_flag_ && !overflow_flag_);
|
||||
case 0x0d: // less than
|
||||
case Condition::LessThan:
|
||||
return (negative_flag_ && !overflow_flag_) || (!negative_flag_ && overflow_flag_);
|
||||
case 0x0e: // greater than
|
||||
case Condition::GreaterThan:
|
||||
return zero_result_ && ((negative_flag_ && overflow_flag_) || (!negative_flag_ && !overflow_flag_));
|
||||
case 0x0f: // less than or equal
|
||||
case Condition::LessThanOrEqual:
|
||||
return !zero_result_ || (negative_flag_ && !overflow_flag_) || (!negative_flag_ && overflow_flag_);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user