1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - library - dsp
3 File: dsp_process.c
4
5 Copyright 2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-11-21#$
14 $Rev: 9387 $
15 $Author: kitase_hirotake $
16 *---------------------------------------------------------------------------*/
17
18
19 #include <twl.h>
20 #include <twl/dsp.h>
21 #include <twl/dsp/common/pipe.h>
22
23 #include "dsp_coff.h"
24
25
26 /*---------------------------------------------------------------------------*/
27 /* Constants */
28
29 #define DSP_DPRINTF(...) ((void) 0)
30 //#define DSP_DPRINTF OS_TPrintf
31
32 // Section enumeration callback in the process image
33 typedef BOOL (*DSPSectionEnumCallback)(DSPProcessContext *, const COFFFileHeader *, const COFFSectionTable *);
34
35
36 /*---------------------------------------------------------------------------*/
37 /* Variables */
38
39 // Process context currently running
40 static DSPProcessContext *DSPiCurrentComponent = NULL;
41 static PMExitCallbackInfo DSPiShutdownCallbackInfo[1];
42 static BOOL DSPiShutdownCallbackIsRegistered = FALSE;
43 static PMSleepCallbackInfo DSPiPreSleepCallbackInfo[1];
44 static BOOL DSPiPreSleepCallbackIsRegistered = FALSE;
45
46
47 /*---------------------------------------------------------------------------*/
48 /* Functions */
49
50 /*---------------------------------------------------------------------------*
51 Name: DSP_EnumSections
52
53 Description: Runs the predetermined processes by enumerating sections in the process image
54
55 Arguments: context: DSPProcessContext structure passed to the callback function
56 callback: Callback called for each section
57
58 Returns: TRUE if all sections are enumerated; FALSE if ended prematurely.
59 *---------------------------------------------------------------------------*/
60 BOOL DSP_EnumSections(DSPProcessContext *context, DSPSectionEnumCallback callback);
61
62 /*---------------------------------------------------------------------------*
63 Name: DSP_StopDSPComponent
64
65 Description: Prepares to end DSP.
66 Currently, only when stopping the DMA of DSP
67
68 Arguments: None.
69
70 Returns: None.
71 *---------------------------------------------------------------------------*/
DSP_StopDSPComponent(void)72 void DSP_StopDSPComponent(void)
73 {
74 DSPProcessContext *context = DSPiCurrentComponent;
75 context->hookFactors = 0;
76 DSP_SendData(DSP_PIPE_COMMAND_REGISTER, DSP_PIPE_FLAG_EXIT_OS);
77 (void)DSP_RecvData(DSP_PIPE_COMMAND_REGISTER);
78 }
79
80 /*---------------------------------------------------------------------------*
81 Name: DSPi_ShutdownCallback
82
83 Description: Forced system shutdown termination callback.
84
85 Arguments: name: Process name
86 Search for processes registered last if NULL is specified
87
88 Returns: DSPProcessContext structure that matches the specified name
89 *---------------------------------------------------------------------------*/
DSPi_ShutdownCallback(void * arg)90 static void DSPi_ShutdownCallback(void *arg)
91 {
92 (void)arg;
93 for (;;)
94 {
95 DSPProcessContext *context = DSP_FindProcess(NULL);
96 if (!context)
97 {
98 break;
99 }
100 // OS_TWarning("force-exit %s component.\n", context->name);
101 DSP_QuitProcess(context);
102 }
103 }
104
105 /*---------------------------------------------------------------------------*
106 Name: DSPi_PreSleepCallback
107
108 Description: Sleep warning callback.
109
110 Arguments: None.
111
112 Returns: None.
113 *---------------------------------------------------------------------------*/
DSPi_PreSleepCallback(void * arg)114 static void DSPi_PreSleepCallback(void *arg)
115 {
116 #pragma unused( arg )
117 OS_Panic("Could not sleep while DSP is processing.\n");
118 }
119
120 /*---------------------------------------------------------------------------*
121 Name: DSPi_MasterInterrupts
122
123 Description: DSP interrupt process.
124
125 Arguments: None.
126
127 Returns: None.
128 *---------------------------------------------------------------------------*/
DSPi_MasterInterrupts(void)129 static void DSPi_MasterInterrupts(void)
130 {
131 DSPProcessContext *context = DSPiCurrentComponent;
132 if (context)
133 {
134 // An interrupt cause flag (IF) is only generated to the OS for the instance that either of the DSP interrupt causes first occurs. If there is the possibility that new DSP interrupt causes can occur while multiple DSP interrupt causes are being sequentially processed, it is necessary to repeat at that time without relying on the interrupt handler.
135 //
136 //
137 //
138 //
139 for (;;)
140 {
141 // Batch determine messages that can be causes of DSP interrupts
142 int ready = (reg_DSP_SEM | (((reg_DSP_PSTS >> REG_DSP_PSTS_RRI0_SHIFT) & 7) << 16));
143 int factors = (ready & context->hookFactors);
144 if (factors == 0)
145 {
146 break;
147 }
148 else
149 {
150 // Process corresponding hook process in order
151 // If group-registered, notify together one time only
152 while (factors != 0)
153 {
154 int index = (int)MATH_CTZ((u32)factors);
155 factors &= ~context->hookGroup[index];
156 (*context->hookFunction[index])(context->hookUserdata[index]);
157 }
158 }
159 }
160 }
161 OS_SetIrqCheckFlag(OS_IE_DSP);
162 }
163
164 /*---------------------------------------------------------------------------*
165 Name: DSPi_ReadProcessImage
166
167 Description: Read data from the process image.
168
169 Arguments: context: DSPProcessContext structure
170 offset: Offset in image
171 buffer: The buffer to transfer to
172 length: Transfer size
173
174 Returns: TRUE, if specified size is correctly read
175 *---------------------------------------------------------------------------*/
DSPi_ReadProcessImage(DSPProcessContext * context,int offset,void * buffer,int length)176 static BOOL DSPi_ReadProcessImage(DSPProcessContext *context, int offset, void *buffer, int length)
177 {
178 return FS_SeekFile(context->image, offset, FS_SEEK_SET) &&
179 (FS_ReadFile(context->image, buffer, length) == length);
180 }
181
182 /*---------------------------------------------------------------------------*
183 Name: DSPi_CommitWram
184
185 Description: Assign specified segment to specific processor.
186
187 Arguments: context: DSPProcessContext structure
188 wram: Code/Data
189 segment: Segment number to switch
190 to: Processor to switch
191
192 Returns: TRUE, if all slots are correctly switched
193 *---------------------------------------------------------------------------*/
DSPi_CommitWram(DSPProcessContext * context,MIWramPos wram,int segment,MIWramProc to)194 static BOOL DSPi_CommitWram(DSPProcessContext *context, MIWramPos wram, int segment, MIWramProc to)
195 {
196 BOOL retval = FALSE;
197 int slot = DSP_GetProcessSlotFromSegment(context, wram, segment);
198 // Disconnect from currently assigned processor
199 if (!MI_IsWramSlotUsed(wram, slot) ||
200 MI_FreeWramSlot(wram, slot, MI_WRAM_SIZE_32KB, MI_GetWramBankMaster(wram, slot)) > 0)
201 {
202 // Assign to specified processor
203 void *physicalAddr = (void *)MI_AllocWramSlot(wram, slot, MI_WRAM_SIZE_32KB, to);
204 if (physicalAddr != 0)
205 {
206 // Move to predetermined offset for each processor
207 vu8 *bank = &((vu8*)((wram == MI_WRAM_B) ? REG_MBK_B0_ADDR : REG_MBK_C0_ADDR))[slot];
208 if (to == MI_WRAM_ARM9)
209 {
210 *bank = (u8)((*bank & ~MI_WRAM_OFFSET_MASK_B) | (slot << MI_WRAM_OFFSET_SHIFT_B));
211 }
212 else if (to == MI_WRAM_DSP)
213 {
214 *bank = (u8)((*bank & ~MI_WRAM_OFFSET_MASK_B) | (segment << MI_WRAM_OFFSET_SHIFT_B));
215 }
216 retval = TRUE;
217 }
218 }
219 return retval;
220 }
221
222
223 /*---------------------------------------------------------------------------*
224 Name: DSPi_MapAndLoadProcessImageCallback
225
226 Description: Callback to map and load with 1 pass of the process image.
227
228 Arguments: context: DSPProcessContext structure
229 header: COFF file header information
230 section: Enumerated section
231
232 Returns: TRUE, if enumeration is continued; FALSE, if acceptable to end
233 *---------------------------------------------------------------------------*/
DSPi_MapAndLoadProcessImageCallback(DSPProcessContext * context,const COFFFileHeader * header,const COFFSectionTable * section)234 static BOOL DSPi_MapAndLoadProcessImageCallback(DSPProcessContext *context,
235 const COFFFileHeader *header,
236 const COFFSectionTable *section)
237 {
238 BOOL retval = TRUE;
239
240 // Because there is possibility that single sections can be located at a maximum of four locations for code and data.
241 //
242 enum
243 {
244 placement_kind_max = 2, // { CODE, DATA }
245 placement_code_page_max = 2,
246 placement_data_page_max = 2,
247 placement_max = placement_code_page_max + placement_data_page_max
248 };
249 MIWramPos wrams[placement_max];
250 int addrs[placement_max];
251 BOOL nolds[placement_max];
252 int placement = 0;
253
254 // Determine the page number to locate using the suffix of the section name
255 // If the name field directly represents the string, it is located in only one position, but if it is a long name that must be referenced from the string table , it is possible to be located in multiple places.
256 //
257 const char *name = (const char *)section->Name;
258 char longname[128];
259 if (*(u32*)name == 0)
260 {
261 u32 stringtable = header->PointerToSymbolTable + 0x12 * header->NumberOfSymbols;
262 if(!DSPi_ReadProcessImage(context,
263 (int)(stringtable + *(u32*)§ion->Name[4]),
264 longname, sizeof(longname)))
265 {
266 retval = FALSE;
267 return retval;
268 }
269 name = longname;
270 }
271
272 // Determine existence of section here that is a special landmark
273 if (STD_CompareString(name, "SDK_USING_OS@d0") == 0)
274 {
275 context->flags |= DSP_PROCESS_FLAG_USING_OS;
276 }
277
278 // CODE section is WRAM-B
279 if ((section->s_flags & COFF_SECTION_ATTR_MAPPED_IN_CODE_MEMORY) != 0)
280 {
281 int baseaddr = (int)(section->s_paddr * 2);
282 BOOL noload = ((section->s_flags & COFF_SECTION_ATTR_NOLOAD_FOR_CODE_MEMORY) != 0);
283 if (STD_StrStr(name, "@c0") != NULL)
284 {
285 wrams[placement] = MI_WRAM_B;
286 addrs[placement] = baseaddr + DSP_WRAM_SLOT_SIZE * 4 * 0;
287 nolds[placement] = noload;
288 ++placement;
289 }
290 if (STD_StrStr(name, "@c1") != NULL)
291 {
292 wrams[placement] = MI_WRAM_B;
293 addrs[placement] = baseaddr + DSP_WRAM_SLOT_SIZE * 4 * 1;
294 nolds[placement] = noload;
295 ++placement;
296 }
297 }
298
299 // DATA section is WRAM-C
300 if ((section->s_flags & COFF_SECTION_ATTR_MAPPED_IN_DATA_MEMORY) != 0)
301 {
302 int baseaddr = (int)(section->s_vaddr * 2);
303 BOOL noload = ((section->s_flags & COFF_SECTION_ATTR_NOLOAD_FOR_DATA_MEMORY) != 0);
304 if (STD_StrStr(name, "@d0") != NULL)
305 {
306 wrams[placement] = MI_WRAM_C;
307 addrs[placement] = baseaddr + DSP_WRAM_SLOT_SIZE * 4 * 0;
308 nolds[placement] = noload;
309 ++placement;
310 }
311 if (STD_StrStr(name, "@d1") != NULL)
312 {
313 wrams[placement] = MI_WRAM_C;
314 addrs[placement] = baseaddr + DSP_WRAM_SLOT_SIZE * 4 * 1;
315 nolds[placement] = noload;
316 ++placement;
317 }
318 }
319
320 // Location destination information was listed up, so locate in each address
321 {
322 int i;
323 for (i = 0; i < placement; ++i)
324 {
325 MIWramPos wram = wrams[i];
326 int dstofs = addrs[i];
327 int length = (int)section->s_size;
328 int srcofs = (int)section->s_scnptr;
329 // Split load so as not to overlap the slot boundary
330 while (length > 0)
331 {
332 // Clip the size at the slot boundary
333 int ceil = MATH_ROUNDUP(dstofs + 1, DSP_WRAM_SLOT_SIZE);
334 int curlen = MATH_MIN(length, ceil - dstofs);
335 BOOL newmapped = FALSE;
336 // If the corresponding segment is not yet mapped, map and initialize here
337 if (DSP_GetProcessSlotFromSegment(context, wram, dstofs / DSP_WRAM_SLOT_SIZE) == -1)
338 {
339 int segment = (dstofs / DSP_WRAM_SLOT_SIZE);
340 u16 *slots = (wram == MI_WRAM_B) ? &context->slotB : &context->slotC;
341 int *segbits = (wram == MI_WRAM_B) ? &context->segmentCode : &context->segmentData;
342 int *map = (wram == MI_WRAM_B) ? context->slotOfSegmentCode : context->slotOfSegmentData;
343 int slot = (int)MATH_CountTrailingZeros((u32)*slots);
344 if (slot >= MI_WRAM_B_MAX_NUM)
345 {
346 retval = FALSE;
347 break;
348 }
349 else
350 {
351 newmapped = TRUE;
352 map[segment] = slot;
353 *slots &= ~(1 << slot);
354 *segbits |= (1 << segment);
355 if (!DSPi_CommitWram(context, wram, segment, MI_WRAM_ARM9))
356 {
357 retval = FALSE;
358 break;
359 }
360 }
361 MI_CpuFillFast(DSP_ConvertProcessAddressFromDSP(context, wram,
362 segment * (DSP_WRAM_SLOT_SIZE / 2)),
363 0, DSP_WRAM_SLOT_SIZE);
364 }
365 // If noload is specified, ignore
366 if (nolds[i])
367 {
368 DSP_DPRINTF("$%04X (noload)\n", dstofs);
369 }
370 else
371 {
372 // Calculate the corresponding offset in this time's transfer range
373 u8 *dstbuf = (u8*)DSP_ConvertProcessAddressFromDSP(context, wram, dstofs / 2);
374 if (!DSPi_ReadProcessImage(context, srcofs, dstbuf, curlen))
375 {
376 retval = FALSE;
377 break;
378 }
379 DSP_DPRINTF("$%04X -> mem:%08X\n", dstofs, dstbuf);
380 }
381 srcofs += curlen;
382 dstofs += curlen;
383 length -= curlen;
384 }
385 }
386 }
387
388 return retval;
389 }
390
391 /*---------------------------------------------------------------------------*
392 Name: DSP_InitProcessContext
393
394 Description: Initializes the process information structure.
395
396 Arguments: context: DSPProcessContext structure
397 name: Process name or NULL
398
399 Returns: None.
400 *---------------------------------------------------------------------------*/
DSP_InitProcessContext(DSPProcessContext * context,const char * name)401 void DSP_InitProcessContext(DSPProcessContext *context, const char *name)
402 {
403 int i;
404 int segment;
405 MI_CpuFill8(context, 0, sizeof(*context));
406 context->next = NULL;
407 context->flags = 0;
408 (void)STD_CopyString(context->name, name ? name : "");
409 context->image = NULL;
410 // Make the segment map empty
411 context->segmentCode = 0;
412 context->segmentData = 0;
413 // Make the slot map empty
414 for (segment = 0; segment < MI_WRAM_B_MAX_NUM; ++segment)
415 {
416 context->slotOfSegmentCode[segment] = -1;
417 }
418 for (segment = 0; segment < MI_WRAM_C_MAX_NUM; ++segment)
419 {
420 context->slotOfSegmentData[segment] = -1;
421 }
422 // Make the hook registration state empty
423 context->hookFactors = 0;
424 for (i = 0; i < DSP_HOOK_MAX; ++i)
425 {
426 context->hookFunction[i] = NULL;
427 context->hookUserdata[i] = NULL;
428 context->hookGroup[i] = 0;
429 }
430 }
431
432 /*---------------------------------------------------------------------------*
433 Name: DSP_EnumSections
434
435 Description: Runs the predetermined processes by enumerating sections in the process image.
436
437 Arguments: context: DSPProcessContext structure passed to the callback function
438 callback: Callback called for each section
439
440 Returns: TRUE if all sections are enumerated; FALSE if ended prematurely.
441 *---------------------------------------------------------------------------*/
DSP_EnumSections(DSPProcessContext * context,DSPSectionEnumCallback callback)442 BOOL DSP_EnumSections(DSPProcessContext *context, DSPSectionEnumCallback callback)
443 {
444 BOOL retval = FALSE;
445 // Copy once to temporary, considering the memory alignment of the image buffer
446 COFFFileHeader header[1];
447 if (DSPi_ReadProcessImage(context, 0, header, sizeof(header)))
448 {
449 int base = (int)(sizeof(header) + header->SizeOfOptionalHeader);
450 int index;
451 for (index = 0; index < header->NumberOfSections; ++index)
452 {
453 COFFSectionTable section[1];
454 if (!DSPi_ReadProcessImage(context, (int)(base + index * sizeof(section)), section, (int)sizeof(section)))
455 {
456 break;
457 }
458 // Sort only sections with a size over 1 and no BLOCK-HEADER attribute
459 if (((section->s_flags & COFF_SECTION_ATTR_BLOCK_HEADER) == 0) && (section->s_size != 0))
460 {
461 if (callback && !(*callback)(context, header, section))
462 {
463 break;
464 }
465 }
466 }
467 retval = (index >= header->NumberOfSections);
468 }
469 return retval;
470 }
471
472 /*---------------------------------------------------------------------------*
473 Name: DSP_AttachProcessMemory
474
475 Description: Assigns memory space continuously to unused regions of the process.
476
477 Arguments: context: DSPProcessContext structure
478 wram: Memory space to assign (MI_WRAM_B/MI_WRAM_C)
479 slots: WRAM slot to assign
480
481 Returns: Header address of the assigned DSP memory space, or 0
482 *---------------------------------------------------------------------------*/
DSP_AttachProcessMemory(DSPProcessContext * context,MIWramPos wram,int slots)483 u32 DSP_AttachProcessMemory(DSPProcessContext *context, MIWramPos wram, int slots)
484 {
485 u32 retval = 0;
486 int *segbits = (wram == MI_WRAM_B) ? &context->segmentCode : &context->segmentData;
487 int *map = (wram == MI_WRAM_B) ? context->slotOfSegmentCode : context->slotOfSegmentData;
488 // Search for continuous unusued regions only for the necessary amount
489 int need = (int)MATH_CountPopulation((u32)slots);
490 u32 region = (u32)((1 << need) - 1);
491 u32 space = (u32)(~*segbits & 0xFF);
492 int segment = 0;
493 for (segment = 0; segment < MI_WRAM_B_MAX_NUM; ++segment)
494 {
495 // There are various restrictions in the DSP page boundary (4 segments) so be careful to allocate without overlap
496 //
497 if ((((segment ^ (segment + need - 1)) & 4) == 0) &&
498 (((space >> segment) & region) == region))
499 {
500 // If there is an adequate unused region existing, assign slots from a lower order
501 retval = (u32)(DSP_ADDR_TO_DSP(DSP_WRAM_SLOT_SIZE) * segment);
502 while (slots)
503 {
504 int slot = (int)MATH_CountTrailingZeros((u32)slots);
505 map[segment] = slot;
506 slots &= ~(1 << slot);
507 *segbits |= (1 << segment);
508 segment += 1;
509 }
510 break;
511 }
512 }
513 return retval;
514 }
515
516 /*---------------------------------------------------------------------------*
517 Name: DSP_DetachProcessMemory
518
519 Description: Deallocates the WRAM slots assigned to the regions used by the process.
520
521 Arguments: context: DSPProcessContext structure
522 slots: Assigned WRAM slot
523
524 Returns: None.
525 *---------------------------------------------------------------------------*/
DSP_DetachProcessMemory(DSPProcessContext * context,MIWramPos wram,int slots)526 void DSP_DetachProcessMemory(DSPProcessContext *context, MIWramPos wram, int slots)
527 {
528 int *segbits = (wram == MI_WRAM_B) ? &context->segmentCode : &context->segmentData;
529 int *map = (wram == MI_WRAM_B) ? context->slotOfSegmentCode : context->slotOfSegmentData;
530 int segment;
531 for (segment = 0; segment < MI_WRAM_B_MAX_NUM; ++segment)
532 {
533 if ((((1 << segment) & *segbits) != 0) && (((1 << map[segment]) & slots) != 0))
534 {
535 *segbits &= ~(1 << segment);
536 map[segment] = -1;
537 }
538 }
539 }
540
541 /*---------------------------------------------------------------------------*
542 Name: DSP_SwitchProcessMemory
543
544 Description: Switches DSP address management being used by a specified process.
545
546 Arguments: context: DSPProcessContext structure
547 wram: Memory space to switch (MI_WRAM_B/MI_WRAM_C)
548 address: Header address to switch (Word units of the DSP memory space)
549 length: Memory size to switch (Word units of the DSP memory space)
550 to: New master processor
551
552 Returns: TRUE, if all slots are correctly switched
553 *---------------------------------------------------------------------------*/
DSP_SwitchProcessMemory(DSPProcessContext * context,MIWramPos wram,u32 address,u32 length,MIWramProc to)554 BOOL DSP_SwitchProcessMemory(DSPProcessContext *context, MIWramPos wram, u32 address, u32 length, MIWramProc to)
555 {
556 address = DSP_ADDR_TO_ARM(address);
557 length = DSP_ADDR_TO_ARM(MATH_MAX(length, 1));
558 {
559 int *segbits = (wram == MI_WRAM_B) ? &context->segmentCode : &context->segmentData;
560 int lower = (int)(address / DSP_WRAM_SLOT_SIZE);
561 int upper = (int)((address + length - 1) / DSP_WRAM_SLOT_SIZE);
562 int segment;
563 for (segment = lower; segment <= upper; ++segment)
564 {
565 if ((*segbits & (1 << segment)) != 0)
566 {
567 if (!DSPi_CommitWram(context, wram, segment, to))
568 {
569 return FALSE;
570 }
571 }
572 }
573 }
574 return TRUE;
575 }
576
577 /*---------------------------------------------------------------------------*
578 Name: DSP_MapAndLoadProcessImage
579
580 Description: Maps and loads with one pass of the specified process image.
581 Segment map does not need to be calculated
582
583 Arguments: context: DSPProcessContext structure
584 image: File handle that specifies the process image
585 Referenced only in this function
586 slotB: WRAM-B allowed for use for code memory
587 slotC: WRAM-C allowed for use for data memory
588
589 Returns: TRUE if all images are correctly loaded
590 *---------------------------------------------------------------------------*/
DSP_MapAndLoadProcessImage(DSPProcessContext * context,FSFile * image,int slotB,int slotC)591 static BOOL DSP_MapAndLoadProcessImage(DSPProcessContext *context, FSFile *image, int slotB, int slotC)
592 {
593 BOOL retval = FALSE;
594 const u32 dspMemSize = DSP_ADDR_TO_DSP(DSP_WRAM_SLOT_SIZE) * MI_WRAM_B_MAX_NUM;
595 // Map WRAM while actually loading the process image
596 context->image = image;
597 context->slotB = (u16)slotB;
598 context->slotC = (u16)slotC;
599
600 if (DSP_EnumSections(context, DSPi_MapAndLoadProcessImageCallback))
601 {
602 DC_FlushRange((const void*)MI_GetWramMapStart_B(), MI_WRAM_B_SIZE);
603 DC_FlushRange((const void*)MI_GetWramMapStart_C(), MI_WRAM_C_SIZE);
604 // Switch all assigned WRAM slots to DSP
605 if (DSP_SwitchProcessMemory(context, MI_WRAM_B, 0, dspMemSize, MI_WRAM_DSP) &&
606 DSP_SwitchProcessMemory(context, MI_WRAM_C, 0, dspMemSize, MI_WRAM_DSP))
607 {
608 retval = TRUE;
609 }
610 }
611 return retval;
612 }
613
614 /*---------------------------------------------------------------------------*
615 Name: DSP_SetProcessHook
616
617 Description: Sets the hook for DSP interrupt cause to the process.
618
619 Arguments: context: DSPProcessContext structure
620 factors: Bit set of the specified interrupt cause
621 Bits 0 - 15 are semaphore; bits 16 - 18 are reply
622 function: Hook function to call
623 userdata: Arbitrary user-defined argument given to the hook function
624
625 Returns: None.
626 *---------------------------------------------------------------------------*/
DSP_SetProcessHook(DSPProcessContext * context,int factors,DSPHookFunction function,void * userdata)627 void DSP_SetProcessHook(DSPProcessContext *context, int factors, DSPHookFunction function, void *userdata)
628 {
629 OSIntrMode bak_cpsr = OS_DisableInterrupts();
630 int i;
631 for (i = 0; i < DSP_HOOK_MAX; ++i)
632 {
633 int bit = (1 << i);
634 if ((bit & factors) != 0)
635 {
636 context->hookFunction[i] = function;
637 context->hookUserdata[i] = userdata;
638 context->hookGroup[i] = factors;
639 }
640 }
641 {
642 // Change the interrupt cause
643 int modrep = (((factors >> 16) & 0x7) << REG_DSP_PCFG_PRIE0_SHIFT);
644 int modsem = ((factors >> 0) & 0xFFFF);
645 int currep = reg_DSP_PCFG;
646 int cursem = reg_DSP_PMASK;
647 if (function != NULL)
648 {
649 reg_DSP_PCFG = (u16)(currep | modrep);
650 reg_DSP_PMASK = (u16)(cursem & ~modsem);
651 context->hookFactors |= factors;
652 }
653 else
654 {
655 reg_DSP_PCFG = (u16)(currep & ~modrep);
656 reg_DSP_PMASK = (u16)(cursem | modsem);
657 context->hookFactors &= ~factors;
658 }
659 }
660 (void)OS_RestoreInterrupts(bak_cpsr);
661 }
662
663 /*---------------------------------------------------------------------------*
664 Name: DSP_HookPostStartProcess
665
666 Description: Hooks immediately after loading the DSP process image.
667 It is necessary for the DSP component developer to start the debugger
668
669 Arguments: None.
670
671 Returns: None.
672 *---------------------------------------------------------------------------*/
DSP_HookPostStartProcess(void)673 SDK_WEAK_SYMBOL void DSP_HookPostStartProcess(void)
674 {
675 }
676
677 /*---------------------------------------------------------------------------*
678 Name: DSP_ExecuteProcess
679
680 Description: Loads the DSP process image and starts.
681
682 Arguments: context: DSPProcessContext structure used in status management
683 Referenced using the system until the process is destroyed
684 image: File handle that specifies the process image
685 Referenced only in this function
686 slotB: WRAM-B allowed for use for code memory
687 slotC: WRAM-C allowed for use for data memory
688
689 Returns: None.
690 *---------------------------------------------------------------------------*/
DSP_ExecuteProcess(DSPProcessContext * context,FSFile * image,int slotB,int slotC)691 BOOL DSP_ExecuteProcess(DSPProcessContext *context, FSFile *image, int slotB, int slotC)
692 {
693 BOOL retval = FALSE;
694 if (!FS_IsAvailable())
695 {
696 OS_TWarning("FS is not initialized yet.\n");
697 FS_Init(FS_DMA_NOT_USE);
698 }
699 // Initialize DSP systems common to all components
700 DSP_InitPipe();
701 OS_SetIrqFunction(OS_IE_DSP, DSPi_MasterInterrupts);
702 DSP_SetProcessHook(context,
703 DSP_HOOK_SEMAPHORE_(15) | DSP_HOOK_REPLY_(2),
704 (DSPHookFunction)DSP_HookPipeNotification, NULL);
705 (void)OS_EnableIrqMask(OS_IE_DSP);
706 // Map the process image to memory and load
707 if (!DSP_MapAndLoadProcessImage(context, image, slotB, slotC))
708 {
709 OS_TWarning("you should check wram\n");
710 }
711 else
712 {
713 OSIntrMode bak_cpsr = OS_DisableInterrupts();
714 // Register the context to the process list
715 DSPProcessContext **pp = &DSPiCurrentComponent;
716 for (pp = &DSPiCurrentComponent; *pp && (*pp != context); pp = &(*pp)->next)
717 {
718 }
719 *pp = context;
720 context->image = NULL;
721 // Set the shutdown forced termination callback
722 if (!DSPiShutdownCallbackIsRegistered)
723 {
724 PM_SetExitCallbackInfo(DSPiShutdownCallbackInfo, DSPi_ShutdownCallback, NULL);
725 PMi_InsertPostExitCallbackEx(DSPiShutdownCallbackInfo, PM_CALLBACK_PRIORITY_DSP);
726 DSPiShutdownCallbackIsRegistered = TRUE;
727 }
728 // Set the sleep warning callback
729 if (!DSPiPreSleepCallbackIsRegistered)
730 {
731 PM_SetSleepCallbackInfo(DSPiPreSleepCallbackInfo, DSPi_PreSleepCallback, NULL);
732 PMi_InsertPreSleepCallbackEx(DSPiPreSleepCallbackInfo, PM_CALLBACK_PRIORITY_DSP);
733 DSPiPreSleepCallbackIsRegistered = TRUE;
734 }
735 // Set only the necessary interrupt cause as early as possible after starting up
736 DSP_PowerOn();
737 DSP_ResetOffEx((u16)(context->hookFactors >> 16));
738 DSP_MaskSemaphore((u16)~(context->hookFactors >> 0));
739 // If the ARM side is paused immediately after startup, it is possible to reload and trace the same component
740 //
741 DSP_HookPostStartProcess();
742 // For components that spontaneously send commands from the DSP side without waiting for command from the ARM9 processor, if reloaded by the DSP debugger, the command value will be initialized to 0 and unread bits will remain on the ARM9 processor.
743 //
744 //
745 //
746 // This 0 is read and discarded in the library
747 if ((context->flags & DSP_PROCESS_FLAG_USING_OS) != 0)
748 {
749 u16 id;
750 for (id = 0; id < 3; ++id)
751 {
752 vu16 dummy;
753 while (dummy = DSP_RecvDataCore(id), dummy != 1)
754 {
755 }
756 }
757 }
758 // Just in case, check whether there is an interrupt that was not taken in the time from startup until setting
759 DSPi_MasterInterrupts();
760 retval = TRUE;
761 (void)OS_RestoreInterrupts(bak_cpsr);
762 }
763 return retval;
764 }
765
766 /*---------------------------------------------------------------------------*
767 Name: DSP_QuitProcess
768
769 Description: Deallocates memory by ending the DSP process.
770
771 Arguments: context: DSPProcessContext structure used in status management
772
773 Returns: None.
774 *---------------------------------------------------------------------------*/
DSP_QuitProcess(DSPProcessContext * context)775 void DSP_QuitProcess(DSPProcessContext *context)
776 {
777 OSIntrMode bak_cpsr;
778
779 // First, stop the TEAK DMA
780 DSP_StopDSPComponent();
781
782 bak_cpsr = OS_DisableInterrupts();
783 // Stop the DSP
784 DSP_ResetOn();
785 DSP_PowerOff();
786 // Invalidate interrupts
787 (void)OS_DisableIrqMask(OS_IE_DSP);
788 OS_SetIrqFunction(OS_IE_DSP, NULL);
789 // Return all WRAM that were being used
790 (void)MI_FreeWram(MI_WRAM_B, MI_WRAM_DSP);
791 (void)MI_FreeWram(MI_WRAM_C, MI_WRAM_DSP);
792 {
793 // Release context from the processor list
794 DSPProcessContext **pp = &DSPiCurrentComponent;
795 for (pp = &DSPiCurrentComponent; *pp; pp = &(*pp)->next)
796 {
797 if (*pp == context)
798 {
799 *pp = (*pp)->next;
800 break;
801 }
802 }
803 context->next = NULL;
804 }
805 (void)context;
806 (void)OS_RestoreInterrupts(bak_cpsr);
807
808 // Delete the warning callback when sleeping
809 PM_DeletePreSleepCallback(DSPiPreSleepCallbackInfo);
810 DSPiPreSleepCallbackIsRegistered = FALSE;
811 }
812
813 /*---------------------------------------------------------------------------*
814 Name: DSP_FindProcess
815
816 Description: Search for the process being run.
817
818 Arguments: name: Process name
819 Search for processes registered last if NULL is specified
820
821 Returns: DSPProcessContext structure that matches the specified name
822 *---------------------------------------------------------------------------*/
DSP_FindProcess(const char * name)823 DSPProcessContext* DSP_FindProcess(const char *name)
824 {
825 DSPProcessContext *ptr = NULL;
826 OSIntrMode bak_cpsr = OS_DisableInterrupts();
827 ptr = DSPiCurrentComponent;
828 if (name)
829 {
830 for (; ptr && (STD_CompareString(ptr->name, name) != 0); ptr = ptr->next)
831 {
832 }
833 }
834 (void)OS_RestoreInterrupts(bak_cpsr);
835 return ptr;
836 }
837
838 /*---------------------------------------------------------------------------*
839 Name: DSP_ReadProcessPipe
840
841 Description: Receives from pipe associated with predetermined port of the process.
842
843 Arguments: context: DSPProcessContext structure
844 port: Reception source port
845 buffer: Received data
846 length: Received size (Byte Units)
847
848 Returns: None.
849 *---------------------------------------------------------------------------*/
DSP_ReadProcessPipe(DSPProcessContext * context,int port,void * buffer,u32 length)850 void DSP_ReadProcessPipe(DSPProcessContext *context, int port, void *buffer, u32 length)
851 {
852 DSPPipe input[1];
853 (void)DSP_LoadPipe(input, port, DSP_PIPE_INPUT);
854 DSP_ReadPipe(input, buffer, (DSPByte)length);
855 (void)context;
856 }
857
858 /*---------------------------------------------------------------------------*
859 Name: DSP_WriteProcessPipe
860
861 Description: Sends to the pipe associated with predetermined port of the process.
862
863 Arguments: context: DSPProcessContext structure
864 port: Reception destination port
865 buffer: Send data
866 length: Send size (Byte Units)
867
868 Returns: None.
869 *---------------------------------------------------------------------------*/
DSP_WriteProcessPipe(DSPProcessContext * context,int port,const void * buffer,u32 length)870 void DSP_WriteProcessPipe(DSPProcessContext *context, int port, const void *buffer, u32 length)
871 {
872 DSPPipe output[1];
873 (void)DSP_LoadPipe(output, port, DSP_PIPE_OUTPUT);
874 DSP_WritePipe(output, buffer, (DSPByte)length);
875 (void)context;
876 }
877
878
879 #if defined(DSP_SUPPORT_OBSOLETE_LOADER)
880 /*---------------------------------------------------------------------------*
881 * The following shows candidate interfaces for termination because they are considered not to be currently in use
882 *---------------------------------------------------------------------------*/
883
884 /*---------------------------------------------------------------------------*
885 Name: DSPi_MapProcessSegmentCallback
886
887 Description: Callback to calculate segment maps occupied by the process.
888
889 Arguments: context: DSPProcessContext structure
890 header: COFF file header information
891 section: Enumerated section
892
893 Returns: TRUE, if enumeration is continued; FALSE, if acceptable to end
894 *---------------------------------------------------------------------------*/
DSPi_MapProcessSegmentCallback(DSPProcessContext * context,const COFFFileHeader * header,const COFFSectionTable * section)895 static BOOL DSPi_MapProcessSegmentCallback(DSPProcessContext *context,
896 const COFFFileHeader *header,
897 const COFFSectionTable *section)
898 {
899 (void)header;
900 // TODO: You might achieve higher speeds by avoiding division
901 if((section->s_flags & COFF_SECTION_ATTR_MAPPED_IN_CODE_MEMORY) != 0)
902 {
903 u32 addr = DSP_ADDR_TO_ARM(section->s_paddr);
904 int lower = (int)(addr / DSP_WRAM_SLOT_SIZE);
905 int upper = (int)((addr + section->s_size - 1) / DSP_WRAM_SLOT_SIZE);
906 int segment;
907 for(segment = lower; segment <= upper; ++segment)
908 {
909 context->segmentCode |= (1 << segment);
910 }
911 }
912 else if((section->s_flags & COFF_SECTION_ATTR_MAPPED_IN_DATA_MEMORY) != 0)
913 {
914 u32 addr = DSP_ADDR_TO_ARM(section->s_vaddr);
915 int lower = (int)(addr / DSP_WRAM_SLOT_SIZE);
916 int upper = (int)((addr + section->s_size - 1) / DSP_WRAM_SLOT_SIZE);
917 int segment;
918 for(segment = lower; segment <= upper; ++segment)
919 {
920 context->segmentData |= (1 << segment);
921 }
922 }
923 return TRUE;
924 }
925
926 /*---------------------------------------------------------------------------*
927 Name: DSPi_MapProcessSlotDefault
928
929 Description: Initializes the slot map using empty numbers from the lower order.
930
931 Arguments: context: DSPProcessContext structure
932 slotB: WRAM-B allowed for use for code memory
933 slotC: WRAM-C allowed for use for data memory
934
935 Returns: TRUE if the slot map that satisfies the conditions can be allocated.
936 *---------------------------------------------------------------------------*/
DSPi_MapProcessSlotDefault(DSPProcessContext * context,int slotB,int slotC)937 static BOOL DSPi_MapProcessSlotDefault(DSPProcessContext *context, int slotB, int slotC)
938 {
939 BOOL retval = TRUE;
940 int segment;
941 for (segment = 0; segment < MI_WRAM_B_MAX_NUM; ++segment)
942 {
943 if ((context->segmentCode & (1 << segment)) != 0)
944 {
945 int slot = (int)MATH_CountTrailingZeros((u32)slotB);
946 if (slot >= MI_WRAM_B_MAX_NUM)
947 {
948 retval = FALSE;
949 break;
950 }
951 context->slotOfSegmentCode[segment] = slot;
952 slotB &= ~(1 << slot);
953 }
954 }
955 for (segment = 0; segment < MI_WRAM_C_MAX_NUM; ++segment)
956 {
957 if ((context->segmentData & (1 << segment)) != 0)
958 {
959 int slot = (int)MATH_CountTrailingZeros((u32)slotC);
960 if (slot >= MI_WRAM_C_MAX_NUM)
961 {
962 retval = FALSE;
963 break;
964 }
965 context->slotOfSegmentData[segment] = slot;
966 slotC &= ~(1 << slot);
967 }
968 }
969 return retval;
970 }
971
972 /*---------------------------------------------------------------------------*
973 Name: DSP_IsProcessMemoryReady
974
975 Description: Checks whether the WRAM slot that should be assigned to the process is being used.
976
977 Arguments: context: DSPProcessContext structure
978
979 Returns: TRUE, if all WRAM slots are not being used but are in a prepared state
980 *---------------------------------------------------------------------------*/
DSP_IsProcessMemoryReady(DSPProcessContext * context)981 static BOOL DSP_IsProcessMemoryReady(DSPProcessContext *context)
982 {
983 BOOL retval = TRUE;
984 int segment;
985 for (segment = 0; segment < MI_WRAM_B_MAX_NUM; ++segment)
986 {
987 if ((context->segmentCode & (1 << segment)) != 0)
988 {
989 int slot = context->slotOfSegmentCode[segment];
990 if (MI_IsWramSlotUsed(MI_WRAM_B, slot))
991 {
992 OS_TWarning("slot:%d for DSP:%05X is now used by someone.\n", slot, segment * DSP_WRAM_SLOT_SIZE);
993 retval = FALSE;
994 break;
995 }
996 }
997 }
998 for (segment = 0; segment < MI_WRAM_C_MAX_NUM; ++segment)
999 {
1000 if ((context->segmentData & (1 << segment)) != 0)
1001 {
1002 int slot = context->slotOfSegmentData[segment];
1003 if (MI_IsWramSlotUsed(MI_WRAM_C, slot))
1004 {
1005 OS_TWarning("slot:%d for DSP:%05X is now used by someone.\n", slot, segment * DSP_WRAM_SLOT_SIZE);
1006 retval = FALSE;
1007 break;
1008 }
1009 }
1010 }
1011 return retval;
1012 }
1013
1014 /*---------------------------------------------------------------------------*
1015 Name: DSPi_LoadProcessImageCallback
1016
1017 Description: Loads the process image using the group method.
1018
1019 Arguments: context: DSPProcessContext structure
1020 header: COFF file header information
1021 section: Enumerated section
1022
1023 Returns: TRUE, if enumeration is continued; FALSE, if acceptable to end
1024 *---------------------------------------------------------------------------*/
DSPi_LoadProcessImageCallback(DSPProcessContext * context,const COFFFileHeader * header,const COFFSectionTable * section)1025 static BOOL DSPi_LoadProcessImageCallback(DSPProcessContext *context,
1026 const COFFFileHeader *header,
1027 const COFFSectionTable *section)
1028 {
1029 BOOL retval = TRUE;
1030 MIWramPos wram = MI_WRAM_A;
1031 int dstofs = 0;
1032 BOOL noload = FALSE;
1033 (void)header;
1034 // CODE section is WRAM-B
1035 if ((section->s_flags & COFF_SECTION_ATTR_MAPPED_IN_CODE_MEMORY) != 0)
1036 {
1037 wram = MI_WRAM_B;
1038 dstofs = (int)(section->s_paddr * 2);
1039 if ((section->s_flags & COFF_SECTION_ATTR_NOLOAD_FOR_CODE_MEMORY) != 0)
1040 {
1041 noload = TRUE;
1042 }
1043 }
1044 // DATA section is WRAM-C
1045 else if ((section->s_flags & COFF_SECTION_ATTR_MAPPED_IN_DATA_MEMORY) != 0)
1046 {
1047 wram = MI_WRAM_C;
1048 dstofs = (int)(section->s_vaddr * 2);
1049 if ((section->s_flags & COFF_SECTION_ATTR_NOLOAD_FOR_DATA_MEMORY) != 0)
1050 {
1051 noload = TRUE;
1052 }
1053 }
1054 // Select the appropriate WRAM slot for each segment
1055 // (The constant "no WRAM" does not exist, so substitute WRAM-A)
1056 if (wram != MI_WRAM_A)
1057 {
1058 // If noload is specified, ignore
1059 if (noload)
1060 {
1061 DSP_DPRINTF("$%04X (noload)\n", dstofs);
1062 }
1063 else
1064 {
1065 // Split load so as not to overlap the slot boundary
1066 int length = (int)section->s_size;
1067 int srcofs = (int)section->s_scnptr;
1068 while (length > 0)
1069 {
1070 // Clip the size at the slot boundary
1071 int ceil = MATH_ROUNDUP(dstofs + 1, DSP_WRAM_SLOT_SIZE);
1072 int curlen = MATH_MIN(length, ceil - dstofs);
1073 // Calculate the corresponding offset in this time's transfer range
1074 u8 *dstbuf = (u8*)DSP_ConvertProcessAddressFromDSP(context, wram, dstofs/2);
1075 if (!DSPi_ReadProcessImage(context, srcofs, dstbuf, length))
1076 {
1077 retval = FALSE;
1078 break;
1079 }
1080 DSP_DPRINTF("$%04X -> mem:%08X\n", dstofs, dstbuf);
1081 srcofs += curlen;
1082 dstofs += curlen;
1083 length -= curlen;
1084 }
1085 }
1086 }
1087 return retval;
1088 }
1089
1090 /*---------------------------------------------------------------------------*
1091 Name: DSP_MapProcessSegment
1092
1093 Description: Calculates segment maps occupied by the process.
1094
1095 Arguments: context: DSPProcessContext structure
1096
1097 Returns: None.
1098 *---------------------------------------------------------------------------*/
DSP_MapProcessSegment(DSPProcessContext * context)1099 void DSP_MapProcessSegment(DSPProcessContext *context)
1100 {
1101 (void)DSP_EnumSections(context, DSPi_MapProcessSegmentCallback);
1102 }
1103
1104 /*---------------------------------------------------------------------------*
1105 Name: DSP_LoadProcessImage
1106
1107 Description: Loads the specified process image.
1108 The segment map must already be calculated.
1109
1110 Arguments: context: DSPProcessContext structure
1111
1112 Returns: TRUE if all images are correctly loaded
1113 *---------------------------------------------------------------------------*/
DSP_LoadProcessImage(DSPProcessContext * context)1114 BOOL DSP_LoadProcessImage(DSPProcessContext *context)
1115 {
1116 BOOL retval = FALSE;
1117 // Check whether it is really possible to use the WRAM slot that should be assigned to DSP
1118 if (DSP_IsProcessMemoryReady(context))
1119 {
1120 const u32 dspMemSize = DSP_ADDR_TO_DSP(DSP_WRAM_SLOT_SIZE) * MI_WRAM_B_MAX_NUM;
1121 // Switch all assigned WRAM slots to ARM9
1122 if (DSP_SwitchProcessMemory(context, MI_WRAM_B, 0, dspMemSize, MI_WRAM_ARM9) &&
1123 DSP_SwitchProcessMemory(context, MI_WRAM_C, 0, dspMemSize, MI_WRAM_ARM9))
1124 {
1125 // Actually load the process image and flush to WRAM
1126 if (DSP_EnumSections(context, DSPi_LoadProcessImageCallback))
1127 {
1128 DC_FlushRange((const void*)MI_GetWramMapStart_B(), MI_WRAM_B_SIZE);
1129 DC_FlushRange((const void*)MI_GetWramMapStart_C(), MI_WRAM_C_SIZE);
1130 // Switch all assigned WRAM slots to DSP
1131 if (DSP_SwitchProcessMemory(context, MI_WRAM_B, 0, dspMemSize, MI_WRAM_DSP) &&
1132 DSP_SwitchProcessMemory(context, MI_WRAM_C, 0, dspMemSize, MI_WRAM_DSP))
1133 {
1134 retval = TRUE;
1135 }
1136 }
1137 }
1138 }
1139 return retval;
1140 }
1141
1142 /*---------------------------------------------------------------------------*
1143 Name: DSP_StartupProcess
1144
1145 Description: Calculates the process image segment map and loads to WRAM.
1146 Version combining the DSP_MapProcessSegment and the DSP_LoadProcessImage functions.
1147
1148 Arguments: context: DSPProcessContext structure
1149 image: File handle that specifies the process image
1150 Referenced only in this function
1151 slotB: WRAM-B allowed for use for code memory
1152 slotC: WRAM-C allowed for use for data memory
1153 slotMapper: Algorithm that assigns WRAM slots to segments
1154 If NULL is specified, the optimum default process is selected
1155
1156 Returns: TRUE if all images are correctly loaded
1157 *---------------------------------------------------------------------------*/
DSP_StartupProcess(DSPProcessContext * context,FSFile * image,int slotB,int slotC,BOOL (* slotMapper)(DSPProcessContext *,int,int))1158 BOOL DSP_StartupProcess(DSPProcessContext *context, FSFile *image,
1159 int slotB, int slotC, BOOL (*slotMapper)(DSPProcessContext *, int, int))
1160 {
1161 BOOL retval = FALSE;
1162 if (!slotMapper)
1163 {
1164 slotMapper = DSPi_MapProcessSlotDefault;
1165 }
1166 if (!FS_IsAvailable())
1167 {
1168 OS_TWarning("FS is not initialized yet.\n");
1169 FS_Init(FS_DMA_NOT_USE);
1170 }
1171 context->image = image;
1172 DSP_MapProcessSegment(context);
1173 if (!(*slotMapper)(context, slotB, slotC) ||
1174 !DSP_LoadProcessImage(context))
1175 {
1176 OS_TWarning("you should check wram\n");
1177 }
1178 else
1179 {
1180 retval = TRUE;
1181 }
1182 context->image = NULL;
1183 return retval;
1184 }
1185
1186
1187 #endif
1188
1189 /*---------------------------------------------------------------------------*
1190 End of file
1191 *---------------------------------------------------------------------------*/
1192