1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-01-23 16:16:16 +00:00
Files
CLK/InstructionSets/x86/Exceptions.hpp
2025-08-08 09:43:16 -04:00

169 lines
3.6 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// Interrupts.hpp
// Clock Signal
//
// Created by Thomas Harte on 06/10/2023.
// Copyright © 2023 Thomas Harte. All rights reserved.
//
#pragma once
#include <cassert>
#include <cstdint>
namespace InstructionSet::x86 {
enum class Vector: uint8_t {
//
// Present on all devices.
//
DivideError = 0,
SingleStep = 1,
NMI = 2,
Breakpoint = 3,
Overflow = 4,
BoundRangeExceeded = 5,
//
// Added by the 80286.
//
InvalidOpcode = 6,
DeviceNotAvailable = 7,
DoubleFault = 8,
CoprocessorSegmentOverrun = 9,
InvalidTSS = 10,
SegmentNotPresent = 11,
StackSegmentFault = 12,
GeneralProtectionFault = 13,
FloatingPointException = 16,
//
// Added by the 80286.
//
PageFault = 14,
AlignmentCheck = 17,
MachineCheck = 18,
};
constexpr bool has_error_code(const Vector vector) {
switch(vector) {
using enum Vector;
case DivideError:
case SingleStep:
case NMI:
case Breakpoint:
case Overflow:
case BoundRangeExceeded:
case InvalidOpcode:
case DeviceNotAvailable:
case CoprocessorSegmentOverrun:
case FloatingPointException:
return false;
case DoubleFault:
case InvalidTSS:
case SegmentNotPresent:
case StackSegmentFault:
case GeneralProtectionFault:
return true;
default: // 386 exceptions; I don't know yet.
break;
}
assert(false);
return false;
}
constexpr bool posts_next_ip(const Vector vector) {
switch(vector) {
using enum Vector;
default:
return false;
case SingleStep:
case Breakpoint:
case Overflow:
return true;
}
}
struct ExceptionCode {
ExceptionCode() = default;
ExceptionCode(
const uint16_t index,
const bool is_local,
const bool is_interrupt,
const bool was_external) noexcept :
value_(
index |
(is_local ? 0x4 : 0x0) |
(is_interrupt ? 0x2 : 0x0) |
(was_external ? 0x1 : 0x0)
) {}
// i.e.:
// b3b15: IDT/GDT/LDT entry
// b2: 1 => in LDT; 0 => in GDT;
// b1: 1 => in IDT, ignore b2; 0 => use b2;
// b0:
// 1 => trigger was external to program code;
// 0 => trigger was caused by the instruction described by the CS:IP that is on the stack.
ExceptionCode(const uint16_t value) :
value_(value) {}
operator uint16_t() const {
return value_;
}
static ExceptionCode zero() {
return ExceptionCode();
}
private:
uint16_t value_ = 0;
};
struct Exception {
ExceptionCode code{}; // Exception code to push to the stack if this is an internal
// exception that provides a code and post_ip_as_code is `false`.
uint8_t vector{}; // Will be equal to value of a `Vector` enum if internal.
enum class CodeType: uint8_t {
Internal,
External,
};
CodeType code_type = CodeType::Internal;
/// Generates an internal exception with no error code.
template <Vector cause>
requires (!has_error_code(cause))
static constexpr Exception exception() {
return Exception(uint8_t(cause));
}
/// Generates an internal exception with a specified error code.
template <Vector cause>
requires (has_error_code(cause))
static constexpr Exception exception(const ExceptionCode code) {
return Exception(uint8_t(cause), code);
}
/// Generates an externally-motivated exception (i.e. an interrupt).
static constexpr Exception interrupt(const uint8_t vector) {
return Exception(vector, CodeType::External);
}
private:
constexpr Exception(const uint8_t vector) noexcept : vector(vector) {}
constexpr Exception(const uint8_t vector, const ExceptionCode code) noexcept : code(code), vector(vector){}
constexpr Exception(const uint8_t vector, const CodeType code_type) noexcept :
vector(vector), code_type(code_type) {}
};
static_assert(sizeof(Exception) <= 4);
}