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