1 #pragma once
2 
3 #include <array>
4 #include <bitset>
5 #include <functional>
6 #include <mutex>
7 #include <utility>
8 #include "common_types.h"
9 
10 namespace Teakra {
11 
12 class ICU {
13 public:
14     using IrqBits = std::bitset<16>;
GetRequest()15     u16 GetRequest() const {
16         std::lock_guard lock(mutex);
17         return (u16)request.to_ulong();
18     }
Acknowledge(u16 irq_bits)19     void Acknowledge(u16 irq_bits) {
20         std::lock_guard lock(mutex);
21         request &= ~IrqBits(irq_bits);
22     }
GetAcknowledge()23     u16 GetAcknowledge() {
24         return 0;
25     }
Trigger(u16 irq_bits)26     void Trigger(u16 irq_bits) {
27         std::lock_guard lock(mutex);
28         IrqBits bits(irq_bits);
29         request |= bits;
30         for (u32 irq = 0; irq < 16; ++irq) {
31             if (bits[irq]) {
32                 for (u32 interrupt = 0; interrupt < enabled.size(); ++interrupt) {
33                     if (enabled[interrupt][irq]) {
34                         on_interrupt(interrupt);
35                     }
36                 }
37                 if (vectored_enabled[irq]) {
38                     on_vectored_interrupt(GetVector(irq), vector_context_switch[irq] != 0);
39                 }
40             }
41         }
42     }
GetTrigger()43     u16 GetTrigger() {
44         return 0;
45     }
TriggerSingle(u32 irq)46     void TriggerSingle(u32 irq) {
47         Trigger(1 << irq);
48     }
SetEnable(u32 interrupt_index,u16 irq_bits)49     void SetEnable(u32 interrupt_index, u16 irq_bits) {
50         std::lock_guard lock(mutex);
51         enabled[interrupt_index] = IrqBits(irq_bits);
52     }
SetEnableVectored(u16 irq_bits)53     void SetEnableVectored(u16 irq_bits) {
54         std::lock_guard lock(mutex);
55         vectored_enabled = IrqBits(irq_bits);
56     }
GetEnable(u32 interrupt_index)57     u16 GetEnable(u32 interrupt_index) const {
58         std::lock_guard lock(mutex);
59         return (u16)enabled[interrupt_index].to_ulong();
60     }
GetEnableVectored()61     u16 GetEnableVectored() const {
62         std::lock_guard lock(mutex);
63         return (u16)vectored_enabled.to_ulong();
64     }
65 
GetVector(u32 irq)66     u32 GetVector(u32 irq) const {
67         return vector_low[irq] | ((u32)vector_high[irq] << 16);
68     }
69 
SetInterruptHandler(std::function<void (u32)> interrupt,std::function<void (u32,bool)> vectored_interrupt)70     void SetInterruptHandler(std::function<void(u32)> interrupt,
71                              std::function<void(u32, bool)> vectored_interrupt) {
72         on_interrupt = std::move(interrupt);
73         on_vectored_interrupt = std::move(vectored_interrupt);
74     }
75 
76     std::array<u16, 16> vector_low, vector_high;
77     std::array<u16, 16> vector_context_switch;
78 
79 private:
80     std::function<void(u32)> on_interrupt;
81     std::function<void(u32, bool)> on_vectored_interrupt;
82 
83     IrqBits request;
84     std::array<IrqBits, 3> enabled;
85     IrqBits vectored_enabled;
86     mutable std::mutex mutex;
87 };
88 
89 } // namespace Teakra
90