1 #include <functional>
2 #include <string>
3 #include <type_traits>
4 #include <vector>
5 #include "ahbm.h"
6 #include "apbp.h"
7 #include "btdmp.h"
8 #include "dma.h"
9 #include "memory_interface.h"
10 #include "mmio.h"
11 #include "timer.h"
12 
13 namespace Teakra {
14 
NoSet(const std::string & debug_string)15 auto NoSet(const std::string& debug_string) {
16     return [debug_string](u16) { printf("Warning: NoSet on %s\n", debug_string.data()); };
17 }
NoGet(const std::string & debug_string)18 auto NoGet(const std::string& debug_string) {
19     return [debug_string]() -> u16 {
20         printf("Warning: NoGet on %s\n", debug_string.data());
21         return 0;
22     };
23 }
24 
25 struct BitFieldSlot {
26     unsigned pos;
27     unsigned length;
28     std::function<void(u16)> set;
29     std::function<u16(void)> get;
30 
31     template <typename T>
RefSlotTeakra::BitFieldSlot32     static BitFieldSlot RefSlot(unsigned pos, unsigned length, T& var) {
33         static_assert(
34             std::is_same_v<u16,
35                            typename std::conditional_t<std::is_enum_v<T>, std::underlying_type<T>,
36                                                        std::enable_if<true, T>>::type>);
37         BitFieldSlot slot{pos, length, {}, {}};
38         slot.set = [&var](u16 value) { var = static_cast<T>(value); };
39         slot.get = [&var]() -> u16 { return static_cast<u16>(var); };
40         return slot;
41     }
42 };
43 
44 struct Cell {
45     std::function<void(u16)> set;
46     std::function<u16(void)> get;
47     u16 index = 0;
48 
CellTeakra::Cell49     Cell(std::function<void(u16)> set, std::function<u16(void)> get)
50         : set(std::move(set)), get(std::move(get)) {}
CellTeakra::Cell51     Cell() {
52         std::shared_ptr<u16> storage = std::make_shared<u16>(0);
53         set = [storage, this](u16 value) {
54             *storage = value;
55             std::printf("MMIO: cell %04X set = %04X\n", index, value);
56         };
57         get = [storage, this]() -> u16 {
58             std::printf("MMIO: cell %04X get\n", index);
59             return *storage;
60         };
61     }
ConstCellTeakra::Cell62     static Cell ConstCell(u16 constant) {
63         Cell cell({}, {});
64         cell.set = NoSet("");
65         cell.get = [constant]() -> u16 { return constant; };
66         return cell;
67     }
RefCellTeakra::Cell68     static Cell RefCell(u16& var) {
69         Cell cell({}, {});
70         cell.set = [&var](u16 value) { var = value; };
71         cell.get = [&var]() -> u16 { return var; };
72         return cell;
73     }
74 
MirrorCellTeakra::Cell75     static Cell MirrorCell(Cell* mirror) {
76         Cell cell({}, {});
77         cell.set = [mirror](u16 value) { mirror->set(value); };
78         cell.get = [mirror]() -> u16 { return mirror->get(); };
79         return cell;
80     }
81 
BitFieldCellTeakra::Cell82     static Cell BitFieldCell(const std::vector<BitFieldSlot>& slots) {
83         Cell cell({}, {});
84         std::shared_ptr<u16> storage = std::make_shared<u16>(0);
85         cell.set = [storage, slots](u16 value) {
86             for (const auto& slot : slots) {
87                 if (slot.set) {
88                     slot.set((value >> slot.pos) & ((1 << slot.length) - 1));
89                 }
90             }
91             *storage = value;
92         };
93         cell.get = [storage, slots]() -> u16 {
94             u16 value = *storage;
95             for (const auto& slot : slots) {
96                 if (slot.get) {
97                     value &= ~(((1 << slot.length) - 1) << slot.pos);
98                     value |= slot.get() << slot.pos;
99                 }
100             }
101             return value;
102         };
103         return cell;
104     }
105 };
106 
107 class MMIORegion::Impl {
108 public:
109     std::array<Cell, 0x800> cells{};
Impl()110     Impl() {
111         for (std::size_t i = 0; i < cells.size(); ++i) {
112             cells[i].index = (u16)i;
113         }
114     }
115 };
116 
MMIORegion(MemoryInterfaceUnit & miu,ICU & icu,Apbp & apbp_from_cpu,Apbp & apbp_from_dsp,std::array<Timer,2> & timer,Dma & dma,Ahbm & ahbm,std::array<Btdmp,2> & btdmp)117 MMIORegion::MMIORegion(MemoryInterfaceUnit& miu, ICU& icu, Apbp& apbp_from_cpu, Apbp& apbp_from_dsp,
118                        std::array<Timer, 2>& timer, Dma& dma, Ahbm& ahbm,
119                        std::array<Btdmp, 2>& btdmp)
120     : impl(new Impl) {
121     using namespace std::placeholders;
122 
123     impl->cells[0x01A] = Cell::ConstCell(0xC902); // chip detect
124 
125     // Timer
126     for (unsigned i = 0; i < 2; ++i) {
127         impl->cells[0x20 + i * 0x10] = Cell::BitFieldCell({
128             // TIMERx_CFG
129             BitFieldSlot::RefSlot(0, 2, timer[i].scale),       // TS
130             BitFieldSlot::RefSlot(2, 3, timer[i].count_mode),  // CM
131             BitFieldSlot{6, 1, {}, {}},                        // TP
132             BitFieldSlot{7, 1, {}, {}},                        // CT
133             BitFieldSlot::RefSlot(8, 1, timer[i].pause),       // PC
134             BitFieldSlot::RefSlot(9, 1, timer[i].update_mmio), // MU
135             BitFieldSlot{10, 1,
136                          [&timer, i](u16 v) {
137                              if (v)
138                                  timer[i].Restart();
139                          },
140                          []() -> u16 { return 0; }}, // RES
141             BitFieldSlot{11, 1, {}, {}},             // BP
142             BitFieldSlot{12, 1, {}, {}},             // CS
143             BitFieldSlot{13, 1, {}, {}},             // GP
144             BitFieldSlot{14, 2, {}, {}},             // TM
145         });
146 
147         impl->cells[0x22 + i * 0x10].set = [&timer, i](u16 v) {
148             if (v)
149                 timer[i].TickEvent();
150         }; // TIMERx_EW
151         impl->cells[0x22 + i * 0x10].get = []() -> u16 { return 0; };
152         impl->cells[0x24 + i * 0x10] = Cell::RefCell(timer[i].start_low);    // TIMERx_SCL
153         impl->cells[0x26 + i * 0x10] = Cell::RefCell(timer[i].start_high);   // TIMERx_SCH
154         impl->cells[0x28 + i * 0x10] = Cell::RefCell(timer[i].counter_low);  // TIMERx_CCL
155         impl->cells[0x2A + i * 0x10] = Cell::RefCell(timer[i].counter_high); // TIMERx_CCH
156         impl->cells[0x2C + i * 0x10] = Cell();                               // TIMERx_SPWMCL
157         impl->cells[0x2E + i * 0x10] = Cell();                               // TIMERx_SPWMCH
158     }
159 
160     // APBP
161     for (unsigned i = 0; i < 3; ++i) {
162         impl->cells[0x0C0 + i * 4].set = std::bind(&Apbp::SendData, &apbp_from_dsp, i, _1);
163         impl->cells[0x0C0 + i * 4].get = std::bind(&Apbp::PeekData, &apbp_from_dsp, i);
164         impl->cells[0x0C2 + i * 4].set = [](u16) {};
165         impl->cells[0x0C2 + i * 4].get = std::bind(&Apbp::RecvData, &apbp_from_cpu, i);
166     }
167     impl->cells[0x0CC].set = std::bind(&Apbp::SetSemaphore, &apbp_from_dsp, _1);
168     impl->cells[0x0CC].get = std::bind(&Apbp::GetSemaphore, &apbp_from_dsp);
169     impl->cells[0x0CE].set = std::bind(&Apbp::MaskSemaphore, &apbp_from_cpu, _1);
170     impl->cells[0x0CE].get = std::bind(&Apbp::GetSemaphoreMask, &apbp_from_cpu);
171     impl->cells[0x0D0].set = std::bind(&Apbp::ClearSemaphore, &apbp_from_cpu, _1);
172     impl->cells[0x0D0].get = []() -> u16 { return 0; };
173     impl->cells[0x0D2].set = [](u16) {};
174     impl->cells[0x0D2].get = std::bind(&Apbp::GetSemaphore, &apbp_from_cpu);
175     impl->cells[0x0D4] = Cell::BitFieldCell({
176         BitFieldSlot{2, 1, {}, {}}, // ARM side endianness flag
177         BitFieldSlot{8, 1,
178                      [&apbp_from_cpu](u16 v) { return apbp_from_cpu.SetDisableInterrupt(0, v); },
179                      [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.GetDisableInterrupt(0); }},
180         BitFieldSlot{12, 1,
181                      [&apbp_from_cpu](u16 v) { return apbp_from_cpu.SetDisableInterrupt(1, v); },
182                      [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.GetDisableInterrupt(1); }},
183         BitFieldSlot{13, 1,
184                      [&apbp_from_cpu](u16 v) { return apbp_from_cpu.SetDisableInterrupt(2, v); },
185                      [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.GetDisableInterrupt(2); }},
186     });
187     impl->cells[0x0D6] = Cell::BitFieldCell({
188         BitFieldSlot{5, 1, {}, [&apbp_from_dsp]() -> u16 { return apbp_from_dsp.IsDataReady(0); }},
189         BitFieldSlot{6, 1, {}, [&apbp_from_dsp]() -> u16 { return apbp_from_dsp.IsDataReady(1); }},
190         BitFieldSlot{7, 1, {}, [&apbp_from_dsp]() -> u16 { return apbp_from_dsp.IsDataReady(2); }},
191         BitFieldSlot{8, 1, {}, [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.IsDataReady(0); }},
192         BitFieldSlot{
193             9, 1, {}, [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.IsSemaphoreSignaled(); }},
194         BitFieldSlot{12, 1, {}, [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.IsDataReady(1); }},
195         BitFieldSlot{13, 1, {}, [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.IsDataReady(2); }},
196     });
197 
198     // This register is a mirror of CPU side register DSP_PSTS
199     impl->cells[0x0D8] = Cell::BitFieldCell({
200         BitFieldSlot{
201             9, 1, {}, [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.IsSemaphoreSignaled(); }},
202         BitFieldSlot{10, 1, {}, [&apbp_from_dsp]() -> u16 { return apbp_from_dsp.IsDataReady(0); }},
203         BitFieldSlot{11, 1, {}, [&apbp_from_dsp]() -> u16 { return apbp_from_dsp.IsDataReady(1); }},
204         BitFieldSlot{12, 1, {}, [&apbp_from_dsp]() -> u16 { return apbp_from_dsp.IsDataReady(2); }},
205         BitFieldSlot{13, 1, {}, [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.IsDataReady(0); }},
206         BitFieldSlot{14, 1, {}, [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.IsDataReady(1); }},
207         BitFieldSlot{15, 1, {}, [&apbp_from_cpu]() -> u16 { return apbp_from_cpu.IsDataReady(2); }},
208     });
209 
210     // AHBM
211     impl->cells[0x0E0].set = NoSet("AHBM::BusyFlag");
212     impl->cells[0x0E0].get = std::bind(&Ahbm::GetBusyFlag, &ahbm);
213     for (u16 i = 0; i < 3; ++i) {
214         impl->cells[0x0E2 + i * 6] = Cell::BitFieldCell({
215             // BitFieldSlot{0, 1, ?, ?},
216             BitFieldSlot{1, 2, std::bind(&Ahbm::SetBurstSize, &ahbm, i, _1),
217                          std::bind(&Ahbm::GetBurstSize, &ahbm, i)},
218             BitFieldSlot{4, 2, std::bind(&Ahbm::SetUnitSize, &ahbm, i, _1),
219                          std::bind(&Ahbm::GetUnitSize, &ahbm, i)},
220         });
221         impl->cells[0x0E4 + i * 6] = Cell::BitFieldCell({
222             BitFieldSlot{8, 1, std::bind(&Ahbm::SetDirection, &ahbm, i, _1),
223                          std::bind(&Ahbm::GetDirection, &ahbm, i)},
224             // BitFieldSlot{9, 1, ?, ?},
225         });
226         impl->cells[0x0E6 + i * 6].set = std::bind(&Ahbm::SetDmaChannel, &ahbm, i, _1);
227         impl->cells[0x0E6 + i * 6].get = std::bind(&Ahbm::GetDmaChannel, &ahbm, i);
228     }
229 
230     // MIU
231     // impl->cells[0x100]; // MIU_WSCFG0
232     // impl->cells[0x102]; // MIU_WSCFG1
233     // impl->cells[0x104]; // MIU_Z0WSCFG
234     // impl->cells[0x106]; // MIU_Z1WSCFG
235     // impl->cells[0x108]; // MIU_Z2WSCFG
236     // impl->cells[0x10C]; // MIU_Z3WSCFG
237     impl->cells[0x10E] = Cell::RefCell(miu.x_page); // MIU_XPAGE
238     impl->cells[0x110] = Cell::RefCell(miu.y_page); // MIU_YPAGE
239     impl->cells[0x112] = Cell::RefCell(miu.z_page); // MIU_ZPAGE
240     impl->cells[0x114] = Cell::BitFieldCell({
241         // MIU_PAGE0CFG
242         BitFieldSlot::RefSlot(0, 6, miu.x_size[0]),
243         BitFieldSlot::RefSlot(8, 6, miu.y_size[0]),
244     });
245     impl->cells[0x116] = Cell::BitFieldCell({
246         // MIU_PAGE1CFG
247         BitFieldSlot::RefSlot(0, 6, miu.x_size[1]),
248         BitFieldSlot::RefSlot(8, 6, miu.y_size[1]),
249     });
250     // impl->cells[0x118]; // MIU_OFFPAGECFG
251     impl->cells[0x11A] = Cell::BitFieldCell({
252         BitFieldSlot{0, 1, {}, {}},                 // PP
253         BitFieldSlot{1, 1, {}, {}},                 // TESTP
254         BitFieldSlot{2, 1, {}, {}},                 // INTP
255         BitFieldSlot{4, 1, {}, {}},                 // ZSINGLEP
256         BitFieldSlot::RefSlot(6, 1, miu.page_mode), // PAGEMODE
257     });
258     // impl->cells[0x11C]; // MIU_DLCFG
259     impl->cells[0x11E] = Cell::RefCell(miu.mmio_base); // MIU_MMIOBASE
260     // impl->cells[0x120]; // MIU_OBSCFG
261     // impl->cells[0x122]; // MIU_POLARITY
262 
263     // DMA
264     impl->cells[0x184].set = std::bind(&Dma::EnableChannel, &dma, _1);
265     impl->cells[0x184].get = std::bind(&Dma::GetChannelEnabled, &dma);
266 
267     impl->cells[0x18C].get = []() -> u16 { return 0xFFFF; }; // SEOX ?
268 
269     impl->cells[0x1BE].set = std::bind(&Dma::ActivateChannel, &dma, _1);
270     impl->cells[0x1BE].get = std::bind(&Dma::GetActiveChannel, &dma);
271     impl->cells[0x1C0].set = std::bind(&Dma::SetAddrSrcLow, &dma, _1);
272     impl->cells[0x1C0].get = std::bind(&Dma::GetAddrSrcLow, &dma);
273     impl->cells[0x1C2].set = std::bind(&Dma::SetAddrSrcHigh, &dma, _1);
274     impl->cells[0x1C2].get = std::bind(&Dma::GetAddrSrcHigh, &dma);
275     impl->cells[0x1C4].set = std::bind(&Dma::SetAddrDstLow, &dma, _1);
276     impl->cells[0x1C4].get = std::bind(&Dma::GetAddrDstLow, &dma);
277     impl->cells[0x1C6].set = std::bind(&Dma::SetAddrDstHigh, &dma, _1);
278     impl->cells[0x1C6].get = std::bind(&Dma::GetAddrDstHigh, &dma);
279     impl->cells[0x1C8].set = std::bind(&Dma::SetSize0, &dma, _1);
280     impl->cells[0x1C8].get = std::bind(&Dma::GetSize0, &dma);
281     impl->cells[0x1CA].set = std::bind(&Dma::SetSize1, &dma, _1);
282     impl->cells[0x1CA].get = std::bind(&Dma::GetSize1, &dma);
283     impl->cells[0x1CC].set = std::bind(&Dma::SetSize2, &dma, _1);
284     impl->cells[0x1CC].get = std::bind(&Dma::GetSize2, &dma);
285     impl->cells[0x1CE].set = std::bind(&Dma::SetSrcStep0, &dma, _1);
286     impl->cells[0x1CE].get = std::bind(&Dma::GetSrcStep0, &dma);
287     impl->cells[0x1D0].set = std::bind(&Dma::SetDstStep0, &dma, _1);
288     impl->cells[0x1D0].get = std::bind(&Dma::GetDstStep0, &dma);
289     impl->cells[0x1D2].set = std::bind(&Dma::SetSrcStep1, &dma, _1);
290     impl->cells[0x1D2].get = std::bind(&Dma::GetSrcStep1, &dma);
291     impl->cells[0x1D4].set = std::bind(&Dma::SetDstStep1, &dma, _1);
292     impl->cells[0x1D4].get = std::bind(&Dma::GetDstStep1, &dma);
293     impl->cells[0x1D6].set = std::bind(&Dma::SetSrcStep2, &dma, _1);
294     impl->cells[0x1D6].get = std::bind(&Dma::GetSrcStep2, &dma);
295     impl->cells[0x1D8].set = std::bind(&Dma::SetDstStep2, &dma, _1);
296     impl->cells[0x1D8].get = std::bind(&Dma::GetDstStep2, &dma);
297     impl->cells[0x1DA] = Cell::BitFieldCell({
298         BitFieldSlot{0, 4, std::bind(&Dma::SetSrcSpace, &dma, _1),
299                      std::bind(&Dma::GetSrcSpace, &dma)},
300         BitFieldSlot{4, 4, std::bind(&Dma::SetDstSpace, &dma, _1),
301                      std::bind(&Dma::GetDstSpace, &dma)},
302         // BitFieldSlot{9, 1, ?, ?},
303         BitFieldSlot{10, 1, std::bind(&Dma::SetDwordMode, &dma, _1),
304                      std::bind(&Dma::GetDwordMode, &dma)},
305     });
306     impl->cells[0x1DC].set = std::bind(&Dma::SetY, &dma, _1);
307     impl->cells[0x1DC].get = std::bind(&Dma::GetY, &dma);
308     impl->cells[0x1DE].set = std::bind(&Dma::SetZ, &dma, _1);
309     impl->cells[0x1DE].get = std::bind(&Dma::GetZ, &dma);
310 
311     // ICU
312     impl->cells[0x200].set = NoSet("ICU::GetRequest");
313     impl->cells[0x200].get = std::bind(&ICU::GetRequest, &icu);
314     impl->cells[0x202].set = std::bind(&ICU::Acknowledge, &icu, _1);
315     impl->cells[0x202].get = std::bind(&ICU::GetAcknowledge, &icu);
316     impl->cells[0x204].set = std::bind(&ICU::Trigger, &icu, _1);
317     impl->cells[0x204].get = std::bind(&ICU::GetTrigger, &icu);
318     impl->cells[0x206].set = std::bind(&ICU::SetEnable, &icu, 0, _1);
319     impl->cells[0x206].get = std::bind(&ICU::GetEnable, &icu, 0);
320     impl->cells[0x208].set = std::bind(&ICU::SetEnable, &icu, 1, _1);
321     impl->cells[0x208].get = std::bind(&ICU::GetEnable, &icu, 1);
322     impl->cells[0x20A].set = std::bind(&ICU::SetEnable, &icu, 2, _1);
323     impl->cells[0x20A].get = std::bind(&ICU::GetEnable, &icu, 2);
324     impl->cells[0x20C].set = std::bind(&ICU::SetEnableVectored, &icu, _1);
325     impl->cells[0x20C].get = std::bind(&ICU::GetEnableVectored, &icu);
326     // impl->cells[0x20E]; // polarity for each interrupt?
327     // impl->cells[0x210]; // source type for each interrupt?
328     for (unsigned i = 0; i < 16; ++i) {
329         impl->cells[0x212 + i * 4] = Cell::BitFieldCell({
330             BitFieldSlot::RefSlot(0, 2, icu.vector_high[i]),
331             BitFieldSlot::RefSlot(15, 1, icu.vector_context_switch[i]),
332         });
333         impl->cells[0x214 + i * 4] = Cell::RefCell(icu.vector_low[i]);
334     }
335 
336     // BTDMP
337     for (u16 i = 0; i < 2; ++i) {
338         impl->cells[0x2A2 + i * 0x80].set = std::bind(&Btdmp::SetTransmitClockConfig, &btdmp[i], _1);
339         impl->cells[0x2A2 + i * 0x80].get = std::bind(&Btdmp::GetTransmitClockConfig, &btdmp[i]);
340         impl->cells[0x2BE + i * 0x80].set = std::bind(&Btdmp::SetTransmitEnable, &btdmp[i], _1);
341         impl->cells[0x2BE + i * 0x80].get = std::bind(&Btdmp::GetTransmitEnable, &btdmp[i]);
342         impl->cells[0x2C2 + i * 0x80] = Cell::BitFieldCell({
343             BitFieldSlot{3, 1, {}, std::bind(&Btdmp::GetTransmitFull, &btdmp[i])},
344             BitFieldSlot{4, 1, {}, std::bind(&Btdmp::GetTransmitEmpty, &btdmp[i])},
345         });
346         impl->cells[0x2C6 + i * 0x80].set = std::bind(&Btdmp::Send, &btdmp[i], _1);
347         impl->cells[0x2CA + i * 0x80].set = std::bind(&Btdmp::SetTransmitFlush, &btdmp[i], _1);
348         impl->cells[0x2CA + i * 0x80].get = std::bind(&Btdmp::GetTransmitFlush, &btdmp[i]);
349     }
350 }
351 
352 MMIORegion::~MMIORegion() = default;
353 
Read(u16 addr)354 u16 MMIORegion::Read(u16 addr) {
355     u16 value = impl->cells[addr].get();
356     return value;
357 }
Write(u16 addr,u16 value)358 void MMIORegion::Write(u16 addr, u16 value) {
359     impl->cells[addr].set(value);
360 }
361 } // namespace Teakra
362