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