2022-04-28 19:35:40 +00:00
|
|
|
|
//
|
|
|
|
|
// Status.hpp
|
|
|
|
|
// Clock Signal
|
|
|
|
|
//
|
|
|
|
|
// Created by Thomas Harte on 28/04/2022.
|
|
|
|
|
// Copyright © 2022 Thomas Harte. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#ifndef InstructionSets_M68k_Status_h
|
|
|
|
|
#define InstructionSets_M68k_Status_h
|
|
|
|
|
|
2022-04-30 18:08:51 +00:00
|
|
|
|
#include "Instruction.hpp"
|
|
|
|
|
|
2023-05-10 21:02:18 +00:00
|
|
|
|
namespace InstructionSet::M68k {
|
2022-04-28 19:35:40 +00:00
|
|
|
|
|
2022-05-12 20:23:07 +00:00
|
|
|
|
namespace ConditionCode {
|
|
|
|
|
|
|
|
|
|
static constexpr uint16_t Carry = 1 << 0;
|
|
|
|
|
static constexpr uint16_t Overflow = 1 << 1;
|
|
|
|
|
static constexpr uint16_t Zero = 1 << 2;
|
|
|
|
|
static constexpr uint16_t Negative = 1 << 3;
|
|
|
|
|
static constexpr uint16_t Extend = 1 << 4;
|
|
|
|
|
|
2022-05-25 14:55:03 +00:00
|
|
|
|
static constexpr uint16_t AllConditions = Carry | Overflow | Zero | Negative | Extend;
|
|
|
|
|
|
2022-05-12 20:23:07 +00:00
|
|
|
|
static constexpr uint16_t Supervisor = 1 << 13;
|
|
|
|
|
static constexpr uint16_t Trace = 1 << 15;
|
2022-05-12 15:39:01 +00:00
|
|
|
|
|
2022-05-12 20:23:07 +00:00
|
|
|
|
static constexpr uint16_t InterruptPriorityMask = 0b111 << 8;
|
2022-05-12 12:19:41 +00:00
|
|
|
|
|
2022-05-12 20:23:07 +00:00
|
|
|
|
}
|
2022-05-12 12:19:41 +00:00
|
|
|
|
|
2022-05-12 20:23:07 +00:00
|
|
|
|
|
|
|
|
|
struct Status {
|
|
|
|
|
/// Generally holds an unevaluated flag for potential later lazy evaluation; it'll be zero for one outcome,
|
|
|
|
|
/// non-zero for the other, but no guarantees are made about the potential range of non-zero values.
|
|
|
|
|
using FlagT = uint_fast32_t;
|
2022-05-12 12:19:41 +00:00
|
|
|
|
|
2022-04-28 19:35:40 +00:00
|
|
|
|
/* b15 */
|
2022-05-12 20:23:07 +00:00
|
|
|
|
FlagT trace_flag = 0; // The trace flag is set if and only if this value is non-zero.
|
2022-04-28 19:35:40 +00:00
|
|
|
|
|
|
|
|
|
/* b13 */
|
2022-05-13 11:53:40 +00:00
|
|
|
|
bool is_supervisor = false; // true => processor is in supervisor mode; false => it isn't.
|
2022-04-28 19:35:40 +00:00
|
|
|
|
|
|
|
|
|
/* b7–b9 */
|
2022-05-12 15:39:01 +00:00
|
|
|
|
int interrupt_level = 0; // The direct integer value of the current interrupt level.
|
2022-05-12 20:23:07 +00:00
|
|
|
|
// Values of 8 or greater have undefined meaning.
|
2022-04-28 19:35:40 +00:00
|
|
|
|
|
|
|
|
|
/* b0–b4 */
|
2022-05-12 20:23:07 +00:00
|
|
|
|
FlagT zero_result = 0; // The zero flag is set if and only if this value is zero.
|
|
|
|
|
FlagT carry_flag = 0; // The carry flag is set if and only if this value is non-zero.
|
|
|
|
|
FlagT extend_flag = 0; // The extend flag is set if and only if this value is non-zero.
|
|
|
|
|
FlagT overflow_flag = 0; // The overflow flag is set if and only if this value is non-zero.
|
|
|
|
|
FlagT negative_flag = 0; // The negative flag is set if and only this value is non-zero.
|
2022-04-28 19:35:40 +00:00
|
|
|
|
|
2022-10-18 18:51:51 +00:00
|
|
|
|
/// Sets the negative flag per @c value
|
|
|
|
|
template <typename IntT> void set_negative(IntT value) {
|
|
|
|
|
constexpr auto top_bit = IntT(1 << ((sizeof(IntT) * 8) - 1));
|
|
|
|
|
negative_flag = value & top_bit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets both the negative and zero flags according to @c value.
|
|
|
|
|
template <typename IntT> void set_neg_zero(IntT value) {
|
|
|
|
|
zero_result = value;
|
|
|
|
|
set_negative(value);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-28 19:35:40 +00:00
|
|
|
|
/// Gets the current condition codes.
|
|
|
|
|
constexpr uint16_t ccr() const {
|
|
|
|
|
return
|
2023-05-12 18:14:45 +00:00
|
|
|
|
(carry_flag ? ConditionCode::Carry : 0) |
|
2022-05-12 12:19:41 +00:00
|
|
|
|
(overflow_flag ? ConditionCode::Overflow : 0) |
|
2022-05-12 20:23:07 +00:00
|
|
|
|
(!zero_result ? ConditionCode::Zero : 0) |
|
2022-05-12 12:19:41 +00:00
|
|
|
|
(negative_flag ? ConditionCode::Negative : 0) |
|
|
|
|
|
(extend_flag ? ConditionCode::Extend : 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets the current condition codes.
|
|
|
|
|
constexpr void set_ccr(uint16_t ccr) {
|
|
|
|
|
carry_flag = ccr & ConditionCode::Carry;
|
|
|
|
|
overflow_flag = ccr & ConditionCode::Overflow;
|
|
|
|
|
zero_result = ~ccr & ConditionCode::Zero;
|
|
|
|
|
negative_flag = ccr & ConditionCode::Negative;
|
|
|
|
|
extend_flag = ccr & ConditionCode::Extend;
|
2022-04-28 19:35:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets the current value of the status register.
|
|
|
|
|
constexpr uint16_t status() const {
|
|
|
|
|
return uint16_t(
|
|
|
|
|
ccr() |
|
2022-05-12 12:19:41 +00:00
|
|
|
|
(interrupt_level << 8) |
|
|
|
|
|
(trace_flag ? ConditionCode::Trace : 0) |
|
2022-05-12 20:23:07 +00:00
|
|
|
|
(is_supervisor ? ConditionCode::Supervisor : 0)
|
2022-04-28 19:35:40 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets the current value of the status register;
|
|
|
|
|
/// @returns @c true if the processor finishes in supervisor mode; @c false otherwise.
|
|
|
|
|
constexpr bool set_status(uint16_t status) {
|
|
|
|
|
set_ccr(status);
|
|
|
|
|
|
2022-05-12 12:19:41 +00:00
|
|
|
|
interrupt_level = (status >> 8) & 7;
|
|
|
|
|
trace_flag = status & ConditionCode::Trace;
|
2022-05-13 11:53:40 +00:00
|
|
|
|
is_supervisor = status & ConditionCode::Supervisor;
|
2022-04-28 19:35:40 +00:00
|
|
|
|
|
2022-05-12 12:19:41 +00:00
|
|
|
|
return is_supervisor;
|
2022-04-28 19:35:40 +00:00
|
|
|
|
}
|
2022-04-28 20:54:57 +00:00
|
|
|
|
|
2022-06-01 12:20:33 +00:00
|
|
|
|
/// Adjusts the status for exception processing — sets supervisor mode, disables trace,
|
|
|
|
|
/// and if @c new_interrupt_level is greater than or equal to 0 sets that as the new
|
|
|
|
|
/// interrupt level.
|
|
|
|
|
///
|
|
|
|
|
/// @returns The status prior to those changes.
|
|
|
|
|
uint16_t begin_exception(int new_interrupt_level = -1) {
|
|
|
|
|
const uint16_t initial_status = status();
|
|
|
|
|
|
|
|
|
|
if(new_interrupt_level >= 0) {
|
|
|
|
|
interrupt_level = new_interrupt_level;
|
|
|
|
|
}
|
|
|
|
|
is_supervisor = true;
|
|
|
|
|
trace_flag = 0;
|
|
|
|
|
|
|
|
|
|
return initial_status;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-30 18:08:51 +00:00
|
|
|
|
/// Evaluates @c condition.
|
2022-06-03 12:31:35 +00:00
|
|
|
|
constexpr bool evaluate_condition(Condition condition) const {
|
2022-04-30 18:08:51 +00:00
|
|
|
|
switch(condition) {
|
2022-04-28 20:54:57 +00:00
|
|
|
|
default:
|
2022-04-30 18:08:51 +00:00
|
|
|
|
case Condition::True: return true;
|
|
|
|
|
case Condition::False: return false;
|
2022-05-12 12:19:41 +00:00
|
|
|
|
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;
|
2022-04-30 18:08:51 +00:00
|
|
|
|
case Condition::GreaterThanOrEqual:
|
2022-05-12 12:19:41 +00:00
|
|
|
|
return (negative_flag && overflow_flag) || (!negative_flag && !overflow_flag);
|
2022-04-30 18:08:51 +00:00
|
|
|
|
case Condition::LessThan:
|
2022-05-12 12:19:41 +00:00
|
|
|
|
return (negative_flag && !overflow_flag) || (!negative_flag && overflow_flag);
|
2022-04-30 18:08:51 +00:00
|
|
|
|
case Condition::GreaterThan:
|
2022-05-12 12:19:41 +00:00
|
|
|
|
return zero_result && ((negative_flag && overflow_flag) || (!negative_flag && !overflow_flag));
|
2022-04-30 18:08:51 +00:00
|
|
|
|
case Condition::LessThanOrEqual:
|
2022-05-12 12:19:41 +00:00
|
|
|
|
return !zero_result || (negative_flag && !overflow_flag) || (!negative_flag && overflow_flag);
|
2022-04-28 20:54:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-03 12:31:35 +00:00
|
|
|
|
|
|
|
|
|
/// @returns @c true if an interrupt at level @c level should be accepted; @c false otherwise.
|
|
|
|
|
constexpr bool would_accept_interrupt(int level) const {
|
|
|
|
|
// TODO: is level seven really non-maskable? If so then what mechanism prevents
|
|
|
|
|
// rapid stack overflow upon a level-seven interrupt?
|
|
|
|
|
return level > interrupt_level;
|
|
|
|
|
}
|
2022-04-28 19:35:40 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* InstructionSets_M68k_Status_h */
|