Splitting Assets from Code: Difference between revisions

Jump to navigation Jump to search
Content added Content deleted
(Added a new section that I'm going to need)
(Finished the 'Loading assets from ROM' chapter)
Line 17: Line 17:
Spec file =
Spec file =
Your Spec file, before adding the assets to it, would look something like this:<br>
Your Spec file, before adding the assets to it, would look something like this:<br>
<syntaxhighlight lang="c">
<pre>
beginseg
beginseg
name "code"
name "code"
Line 25: Line 25:
stack NU_SPEC_BOOT_STACK
stack NU_SPEC_BOOT_STACK
include "codesegment.o"
include "codesegment.o"
// Microcode includes here
// Microcode includes go here (omitted for simplicity reasons)
endseg
endseg


Line 33: Line 33:
include "code"
include "code"
endwave
endwave
</syntaxhighlight>
</pre>
Adding in new raw assets is as simple as creating a new segment and specifying the <code>RAW</code> flag. For instance, having the data from <code>spr_bear.c</code> converted into binary form (with the name <code>spr_bear.bin</code>) and linking it to our ROM is as simple as:
Adding in new raw assets is as simple as creating a new segment and specifying the <code>RAW</code> flag. For instance, having the data from <code>spr_bear.c</code> converted into binary form (with the name <code>spr_bear.bin</code>) and linking it to our ROM is as simple as:
<syntaxhighlight lang="c">
<pre>
beginseg
beginseg
name "spr_bear" // This name is important, and should be unique
name "spr_bear" // This name is important, and should be unique
Line 42: Line 42:
include "spr_bear.bin" // The file to link
include "spr_bear.bin" // The file to link
endseg
endseg
</syntaxhighlight>
</pre>
Do this for all the assets, and you're almost done. The next step is to open a C header file (or better yet, create a new one) and to create some <code>extern</code> calls for your new segments:
Do this for all the assets, and you're almost done. The next step is to open a C header file (or better yet, create a new one) and to create some <code>extern</code> calls for your new segments:
<syntaxhighlight lang="c">
<pre>
extern u8 _spr_bearSegmentRomStart[];
extern u32 _spr_bearSegmentRomStart[];
extern u8 _spr_bearSegmentRomEnd[];
extern u32 _spr_bearSegmentRomEnd[];
</syntaxhighlight>
</pre>
Remember that segment name I told you that was important and had to be unique? Whatever you set your segment name to, it needs to match the <code>extern</code>'s. Meaning, if you called your segment <code>NAME</code>, then you would need to define the <code>extern</code>'s as <code>_NAMESegmentRomStart</code> and <code>_NAMESegmentRomEnd</code> respectively.
Remember that segment name I told you that was important and had to be unique? Whatever you set your segment name to, it needs to match the <code>extern</code>'s. Meaning, if you called your segment <code>NAME</code>, then you would need to define the <code>extern</code>'s as <code>_NAMESegmentRomStart</code> and <code>_NAMESegmentRomEnd</code> respectively.


Line 59: Line 59:


== Loading assets from ROM ==
== Loading assets from ROM ==
Having the segment addresses for our data in ROM, it is relatively simple to DMA them from ROM. We know the starting address of our data thanks to the SegmentRomStart, and we can infer the size of the data by subtracting the start address from the end address.
TODO

With Nusys, the task is relatively trivial:
<syntaxhighlight lang="c">
u32 size = _spr_bearSegmentRomEnd - _spr_bearSegmentRomStart;
nuPiReadRom((u32)_spr_bearSegmentRomStart, (void*)buffer, size);
</syntaxhighlight>
If you're not using Nusys, then there's a bit more overhead involved:
<syntaxhighlight lang="c">
OSIoMesg dmaIoMesgBuf; // The message buffer
OSMesgQueue dmaMesgQ; // The message queue
// This code already assumes a message queue exists and has been created with 'osCreateMesgQueue'
// These variables are just here for reference

u32 size = _spr_bearSegmentRomEnd - _spr_bearSegmentRomStart;

// Invalidate data cache for the buffer to prevent memory from being destroyed
osInvalDCache((void*)buffer, size);

// Start the DMA
osPiStartDma(&dmaIoMesgBuf, OS_MESG_PRI_NORMAL, OS_READ, _spr_bearSegmentRomStart, buffer, size, &dmaMesgQ);

// Wait for the DMA to finish
osRecvMesg(&dmaMesgQ, NULL, OS_MESG_BLOCK);
</syntaxhighlight>

Please note that the code on this wiki page '''does not replace the manuals'''. Data DMA has very strict requirements in terms of maximum size and buffer alignment, therefore you should look up the manual pages for <code>nuPiReadRom</code> or <code>osPiStartDma</code> to make sure your DMA operation will succeed.

You're probably wondering from the above code what <code>buffer</code> is. You probably understand that the data needs to go somewhere (like a variable in your code), but there's two different approaches to having data buffers:


== Having a buffer in the codesegment ==
== Having a buffer in the codesegment ==
Line 66: Line 94:
== Having a buffer somewhere in RAM ==
== Having a buffer somewhere in RAM ==
TODO
TODO

== Finalizing the code ==