1 #include <array>
2 #include <atomic>
3 #include "ahbm.h"
4 #include "apbp.h"
5 #include "btdmp.h"
6 #include "core_timing.h"
7 #include "dma.h"
8 #include "icu.h"
9 #include "memory_interface.h"
10 #include "mmio.h"
11 #include "processor.h"
12 #include "shared_memory.h"
13 #include "teakra/teakra.h"
14 #include "timer.h"
15 
16 namespace Teakra {
17 
18 struct Teakra::Impl {
19     CoreTiming core_timing;
20     SharedMemory shared_memory;
21     MemoryInterfaceUnit miu;
22     ICU icu;
23     Apbp apbp_from_cpu, apbp_from_dsp;
24     std::array<Timer, 2> timer{{{core_timing}, {core_timing}}};
25     Ahbm ahbm;
26     Dma dma{shared_memory, ahbm};
27     std::array<Btdmp, 2> btdmp{{{core_timing}, {core_timing}}};
28     MMIORegion mmio{miu, icu, apbp_from_cpu, apbp_from_dsp, timer, dma, ahbm, btdmp};
29     MemoryInterface memory_interface{shared_memory, miu};
30     Processor processor{core_timing, memory_interface};
31 
ImplTeakra::Teakra::Impl32     Impl() {
33         memory_interface.SetMMIO(mmio);
34         using namespace std::placeholders;
35         icu.SetInterruptHandler(std::bind(&Processor::SignalInterrupt, &processor, _1),
36                                 std::bind(&Processor::SignalVectoredInterrupt, &processor, _1, _2));
37 
38         timer[0].SetInterruptHandler([this]() { icu.TriggerSingle(0xA); });
39         timer[1].SetInterruptHandler([this]() { icu.TriggerSingle(0x9); });
40 
41         apbp_from_cpu.SetDataHandler(0, [this]() { icu.TriggerSingle(0xE); });
42         apbp_from_cpu.SetDataHandler(1, [this]() { icu.TriggerSingle(0xE); });
43         apbp_from_cpu.SetDataHandler(2, [this]() { icu.TriggerSingle(0xE); });
44         apbp_from_cpu.SetSemaphoreHandler([this]() { icu.TriggerSingle(0xE); });
45 
46         btdmp[0].SetInterruptHandler([this]() { icu.TriggerSingle(0xB); });
47         btdmp[1].SetInterruptHandler([this]() { icu.TriggerSingle(0xB); });
48 
49         dma.SetInterruptHandler([this]() { icu.TriggerSingle(0xF); });
50     }
51 
ResetTeakra::Teakra::Impl52     void Reset() {
53         shared_memory.raw.fill(0);
54         miu.Reset();
55         apbp_from_cpu.Reset();
56         apbp_from_dsp.Reset();
57         timer[0].Reset();
58         timer[1].Reset();
59         ahbm.Reset();
60         dma.Reset();
61         btdmp[0].Reset();
62         btdmp[1].Reset();
63         processor.Reset();
64     }
65 };
66 
Teakra()67 Teakra::Teakra() : impl(new Impl) {}
68 Teakra::~Teakra() = default;
69 
Reset()70 void Teakra::Reset() {
71     impl->Reset();
72 }
73 
GetDspMemory()74 std::array<std::uint8_t, 0x80000>& Teakra::GetDspMemory() {
75     return impl->shared_memory.raw;
76 }
77 
GetDspMemory() const78 const std::array<std::uint8_t, 0x80000>& Teakra::GetDspMemory() const {
79     return impl->shared_memory.raw;
80 }
81 
Run(unsigned cycle)82 void Teakra::Run(unsigned cycle) {
83     impl->processor.Run(cycle);
84 }
85 
SendDataIsEmpty(std::uint8_t index) const86 bool Teakra::SendDataIsEmpty(std::uint8_t index) const {
87     return !impl->apbp_from_cpu.IsDataReady(index);
88 }
SendData(std::uint8_t index,std::uint16_t value)89 void Teakra::SendData(std::uint8_t index, std::uint16_t value) {
90     impl->apbp_from_cpu.SendData(index, value);
91 }
RecvDataIsReady(std::uint8_t index) const92 bool Teakra::RecvDataIsReady(std::uint8_t index) const {
93     return impl->apbp_from_dsp.IsDataReady(index);
94 }
RecvData(std::uint8_t index)95 std::uint16_t Teakra::RecvData(std::uint8_t index) {
96     return impl->apbp_from_dsp.RecvData(index);
97 }
PeekRecvData(std::uint8_t index)98 std::uint16_t Teakra::PeekRecvData(std::uint8_t index) {
99     return impl->apbp_from_dsp.PeekData(index);
100 }
SetRecvDataHandler(std::uint8_t index,std::function<void ()> handler)101 void Teakra::SetRecvDataHandler(std::uint8_t index, std::function<void()> handler) {
102     impl->apbp_from_dsp.SetDataHandler(index, std::move(handler));
103 }
104 
SetSemaphore(std::uint16_t value)105 void Teakra::SetSemaphore(std::uint16_t value) {
106     impl->apbp_from_cpu.SetSemaphore(value);
107 }
SetSemaphoreHandler(std::function<void ()> handler)108 void Teakra::SetSemaphoreHandler(std::function<void()> handler) {
109     impl->apbp_from_dsp.SetSemaphoreHandler(std::move(handler));
110 }
GetSemaphore() const111 std::uint16_t Teakra::GetSemaphore() const {
112     return impl->apbp_from_dsp.GetSemaphore();
113 }
ClearSemaphore(std::uint16_t value)114 void Teakra::ClearSemaphore(std::uint16_t value) {
115     impl->apbp_from_dsp.ClearSemaphore(value);
116 }
MaskSemaphore(std::uint16_t value)117 void Teakra::MaskSemaphore(std::uint16_t value) {
118     impl->apbp_from_dsp.MaskSemaphore(value);
119 }
SetAHBMCallback(const AHBMCallback & callback)120 void Teakra::SetAHBMCallback(const AHBMCallback& callback) {
121     impl->ahbm.SetExternalMemoryCallback(callback.read8, callback.write8,
122         callback.read16, callback.write16,
123         callback.read32, callback.write32);
124 }
125 
AHBMGetUnitSize(std::uint16_t i) const126 std::uint16_t Teakra::AHBMGetUnitSize(std::uint16_t i) const {
127     return impl->ahbm.GetUnitSize(i);
128 }
AHBMGetDirection(std::uint16_t i) const129 std::uint16_t Teakra::AHBMGetDirection(std::uint16_t i) const {
130     return impl->ahbm.GetDirection(i);
131 }
AHBMGetDmaChannel(std::uint16_t i) const132 std::uint16_t Teakra::AHBMGetDmaChannel(std::uint16_t i) const {
133     return impl->ahbm.GetDmaChannel(i);
134 }
135 
AHBMRead16(std::uint32_t addr)136 std::uint16_t Teakra::AHBMRead16(std::uint32_t addr) {
137     return impl->ahbm.Read16(0, addr);
138 }
AHBMWrite16(std::uint32_t addr,std::uint16_t value)139 void Teakra::AHBMWrite16(std::uint32_t addr, std::uint16_t value) {
140     impl->ahbm.Write16(0, addr, value);
141 }
AHBMRead32(std::uint32_t addr)142 std::uint16_t Teakra::AHBMRead32(std::uint32_t addr) {
143     return impl->ahbm.Read32(0, addr);
144 }
AHBMWrite32(std::uint32_t addr,std::uint32_t value)145 void Teakra::AHBMWrite32(std::uint32_t addr, std::uint32_t value) {
146     impl->ahbm.Write32(0, addr, value);
147 }
148 
SetAudioCallback(std::function<void (std::array<s16,2>)> callback)149 void Teakra::SetAudioCallback(std::function<void(std::array<s16, 2>)> callback) {
150     impl->btdmp[0].SetAudioCallback(std::move(callback));
151 }
152 
ProgramRead(std::uint32_t address) const153 std::uint16_t Teakra::ProgramRead(std::uint32_t address) const {
154     return impl->memory_interface.ProgramRead(address);
155 }
ProgramWrite(std::uint32_t address,std::uint16_t value)156 void Teakra::ProgramWrite(std::uint32_t address, std::uint16_t value) {
157     impl->memory_interface.ProgramWrite(address, value);
158 }
DataRead(std::uint16_t address,bool bypass_mmio)159 std::uint16_t Teakra::DataRead(std::uint16_t address, bool bypass_mmio) {
160     return impl->memory_interface.DataRead(address, bypass_mmio);
161 }
DataWrite(std::uint16_t address,std::uint16_t value,bool bypass_mmio)162 void Teakra::DataWrite(std::uint16_t address, std::uint16_t value, bool bypass_mmio) {
163     impl->memory_interface.DataWrite(address, value, bypass_mmio);
164 }
DataReadA32(std::uint32_t address) const165 std::uint16_t Teakra::DataReadA32(std::uint32_t address) const {
166     return impl->memory_interface.DataReadA32(address);
167 }
DataWriteA32(std::uint32_t address,std::uint16_t value)168 void Teakra::DataWriteA32(std::uint32_t address, std::uint16_t value) {
169     impl->memory_interface.DataWriteA32(address, value);
170 }
MMIORead(std::uint16_t address)171 std::uint16_t Teakra::MMIORead(std::uint16_t address) {
172     return impl->memory_interface.MMIORead(address);
173 }
MMIOWrite(std::uint16_t address,std::uint16_t value)174 void Teakra::MMIOWrite(std::uint16_t address, std::uint16_t value) {
175     impl->memory_interface.MMIOWrite(address, value);
176 }
177 
DMAChan0GetSrcHigh()178 std::uint16_t Teakra::DMAChan0GetSrcHigh() {
179     u16 active_bak = impl->dma.GetActiveChannel();
180     impl->dma.ActivateChannel(0);
181     u16 ret = impl->dma.GetAddrSrcHigh();
182     impl->dma.ActivateChannel(active_bak);
183     return ret;
184 }
DMAChan0GetDstHigh()185 std::uint16_t Teakra::DMAChan0GetDstHigh() {
186     u16 active_bak = impl->dma.GetActiveChannel();
187     impl->dma.ActivateChannel(0);
188     u16 ret = impl->dma.GetAddrDstHigh();
189     impl->dma.ActivateChannel(active_bak);
190     return ret;
191 }
192 
193 } // namespace Teakra
194