[announce] c64_tools (DSP loader and IPC)


my question was to use the qemu code, load it into the dsp and catch some matrix * vertex  operations (if this is possible), and let the dsp do the integer operations needed to perform the x86 floating point operation. the main cpu can do other during this time if possible (like audio procssing).
It can't, because it's all done by the emulated program, and you can't parallelize it if it's not parallel to begin with.
I guess, rohezal aimed at floating point emulation via dsp, what should be possible, though. But I have no clue about the emulation algorithm, so can't say how parallelizable it could be :)

I've actually wanted to try to learn DSP for a while, my stumbling block is that there didn't seem to be any simple interface that made sense to me. Everything I've read about DSPLink and Bridge assumed that you already had some idea of what you were doing. I want a library and tutorial that assumes the user is an idiot.
Thats true. Useful resources are very rare.
 
Last edited by a moderator:
It probably already has been said in this thread, but a new stab at screen filters, scalers, compositors etc would be an excellent starting point/proof of concept for this.
 
@ptitSeb, yeah anyway N64 emu isn't making any progress since a long time so i'm sure plenty of ppl will be happy with some new stuff ^^.
You should wait for a video within the next few days from me, before saying that.


Internal beta testing has shown A LOT of progress during the last weeks with N64.


I'm playing Super Mario 64 with HiRes texture packs, for example :D

Huh !?! Askarus is gonna have a stroke !
What makes you so sure I don't know about it already ;) ?
 
about qemu -- not my expertise but here are some thoughts: the FPU is a coprocessor so you would probably want to use the DSP to emulate the entire x87. You would need to find out when the result of an FPU operation is actually pulled into a virtual X86 register (or mem. location), that's when you need to sync with the DSP. Vice versa: the first FPU operation after a sync would "wake" the DSP, which would then enter what I named a "fastcall sequence" that does not involve (slow) interrupts but does the handshaking with the ARM via SRAM. You would not want to use my dsp_fastcall_rpc() API function for that -- it does error checking, handles DSP timeouts etc. This eats performance so you'll have to do the handshaking yourself (see "dsp.c" in the next c64_tools release). With proper optimization I would estimate that you can do 2 to 3 million handshakes (maybe more?) this way. That's if the SRAM access speed is not the limiting factor, I have not evaluated that, yet (it's probably not, not on the DSP-side for sure).

This sounds like a pretty tough job to me, though.
 
Last edited by a moderator:
EDIT: I have not taken a look at the new kernel sources, yet but is my assumption correct that you check whether the allocation size is 4mbytes and in that case return the DSP image area ?
Nope, it's specifying the dev pointer to dma_alloc_coherent() from a platform_device with name "c64_tools" is the thing that tells it to give you the early-boot-prepared 4MB CMA area at 0x86000000.
 
 
1. Code an audio Plugin for mupen64plus v2. The audio is not a big workload, but if it can be offloaded from main CPU, it will certainly be good. Also, the modular side of mupen64 make it a good canditate to have a DSP Plugin to test, while maintaining compatibility with "not DSP-able system".
At least on mupen64plus v1 audio plugin was only responsible for sending audio to hardware and nothing else, has that changed in v2?
V1 and V2 are very similar for Sound plugin, and I ported your plugin quickly, just a few a change in the EXPORT function, logic stay the same. But I was thinking at handling the Frequency transcoding (when asked frequency from N64 is not supported by OSS) can be handled by the DSP. I was looking at something very simple,

even if not groundbreaking, for a first try at DSP.

I was thinking of that because I did noticed some gain in FPS when switching from mupen-audio-sdl to audio-notaz.
 
Last edited by a moderator:
From the ARM side the SRAM has got to be at least some dozens of cycles to access since it sits on the other side of the L3 interconnect. You may still be able to do a couple million handshakes per second but that's not a useful metric by itself if you have to spend all your CPU time to get it.. You'll have to figure out what the typical overhead cost is and weigh that against the cost of the operation you want on both CPU and DSP side. If we're talking ~300-500 cycles then I'm positive that a properly optimized x87 emulator can beat that for any normal operation. That still doesn't include the cost of the DSP actually performing the operation, neither processor can do this handshaking in the background if it involves polling SRAM.

You really shouldn't look at the x87 in a similar fashion to the DSP, it's not some separate processor that runs doing its own thing, it's much more tightly coupled with the CPU than that.

BTW, if qemu's implementation is really 300 lines of C then probably the bulk of that is tied into code with a lot of control flow stuff, like checking for different FPU states (precision and rounding modes) and exceptions. Stuff that the DSP is bad at.
 
Last edited by a moderator:
EDIT: I have not taken a look at the new kernel sources, yet but is my assumption correct that you check whether the allocation size is 4mbytes and in that case return the DSP image area ?
Nope, it's specifying the dev pointer to dma_alloc_coherent() from a platform_device with name "c64_tools" is the thing that tells it to give you the early-boot-prepared 4MB CMA area at 0x86000000.
goodie, sounds like a clean solution to me then. (and btw, after looking at your testmodule I now understand how one is supposed to build a module that consists of several source files. d'oh! (this is my first kernel module, so I am still learning))
 
@ptitSeb, yeah anyway N64 emu isn't making any progress since a long time so i'm sure plenty of ppl will be happy with some new stuff ^^.
You should wait for a video within the next few days from me, before saying that.
Internal beta testing has shown A LOT of progress during the last weeks with N64.


I'm playing Super Mario 64 with HiRes texture packs, for example :D
I'm smelling notaz :)


Looking forward to that!


sorry for derailing ;-)
 
@ptitSeb, yeah anyway N64 emu isn't making any progress since a long time so i'm sure plenty of ppl will be happy with some new stuff ^^.
You should wait for a video within the next few days from me, before saying that.
Internal beta testing has shown A LOT of progress during the last weeks with N64.


I'm playing Super Mario 64 with HiRes texture packs, for example :D
I'm smelling notaz :)


Looking forward to that!


sorry for derailing ;-)
Nope it's a slightly "smaller" smell! You could say Petit... :p
 
Here's a small benchmark that tests the SRAM speed (on the ARM side). This should give an idea of the maximum number of "messages" that can be sent to the DSP (write) resp. read back. This is a completely synthetic benchmark, of course.


pandora:/home/bsp# ./c64_tc 7
[...] selected testcase 7 ("TC_SRAM_SPEED")
[...] starting SRAM write benchmark....DONE: 10000000 32bit write accesses in 2566 milliseconds
[...] starting SRAM read benchmark....DONE: 10000000 32bit read accesses in 2590 milliseconds (chksum=0xfffffff8)

(i.e. ~3.897 million SRAM reads or writes per second. the ARM is 100% busy doing practically nothing else, of course)

(this is quite OK, though. An Amiga emulator could place the Paula (soundchip) registers in SRAM and the DSP could handle the sound playback w/o much further interaction. /idea)
 
Last edited by a moderator:
Would the OpenDE physics engine (Puzzle Moppet) be reasonably parallizable?
 
@__jr__: if you are a developer, just look at the source and find out :) physics engines in general can be handled by the DSP, although, as said already, the DSP has no FPU so everything *should* be fixed point math (or use TI's float emulation library, see http://processors.wiki.ti.com/index.php?title=Software_libraries).

@WizardStan: I'll see if I can come up with a small tutorial. The c64_tools package should already be quite easy to use without one, though.

So, before the weekend starts, here is the latest release of "c64_tools":


** Changes

20-Sep-2013
- changed: GPP applications do not require root privileges anymore (a bug in the last release)
- GPP applications now have access to the second half of the L1DSRAM of the DSP (24 kbytes)
The last 16 bytes of that area are used as IPC 'registers'. See "include/dsp_common.h".
- added dsp_fastcall_rpc() (can be called after the DSP has initiated a fastcall sequence)
- added dsp_fastcall_end() (must be called to finish the fastcall sequence)
- added dsp_rpc_send() and dsp_rpc_recv() (so that applications can do something else while
the DSP is busy)
- added new DSP "dsp_calc_fastcall" demo component that shows how to implement fastcall RPCs
- added testcase #6 to "tests/c64_tc.c" (fastcall RPC example)
- added testcase #7 to "tests/c64_tc.c" (SRAM access benchmark (=> ~3.89 million 32bit reads/writes per second)
- the "c64.ko" kernel module now allocates the DSP image area (fixed address) during init.
this means that it is no longer necessary to statically reserve memory for the DSP at boot time.
(thanks to Notaz for providing a new Linux kernel and a small example module !)

** NOTE ** You need the updated kernel (see "bin-20Sep2013/uImage-3", copy it to "/boot" on the Pandora)
for the kernel module binary to work.

Please use the "scripts/cma_dsp_mem/autoboot.txt" boot script (works on all Pandora editions).

In case you do not want to update your kernel for some reason, you have to undefine
"USE_PLATFORM_DRIVER" in "c64_kmod/kmod.c" and rebuild the module. You will also need
to use one of the "scripts/static_dsp_mem/*" boot scripts (depends on what edition you have).

p.s.: the updated (23:59) "go64.sh" script fixes the "/dev/c64" permissions after loading the kernel module (which creates the device inode), so that the device is actually accessible for "everyone".

c64_tools-20Sep2013.tar.gz
 

Attachments

  • c64_tools-20Sep2013.tar.gz
    3.6 MB · Views: 392
  • go64.sh.tar.gz
    1 KB · Views: 404
Last edited by a moderator:
bsp, do you have a blocking mode of operation? I've had a quick look and it seems it's polling everywhere with 1us sleeps in between. This wouldn't be that great in multithreaded program with longer DSP tasks, the thread taking care of DSP would spend a lot of time spinning in those poll loops, sleeping and waking, and as we only have 1 ARM core, there would be many context switches to the other thread and back. Instead the DSP-handler thread could go to sleep until DSP is done with the task (which is accomplished with blocking read), and other thread could use ARM solely for itself.

Of course the app could be coded to just use single thread and do work on ARM, occasionally checking how the DSP is doing manually, but it is very inconvenient to do it like that in some cases, the ARM work would have to be chopped into small parts that are similar to tasks for DSP.

Please use the "scripts/cma_dsp_mem/autoboot.txt" boot script (works on all Pandora editions).
Hmm, this is the default default firmware script now, right?
 
Last edited by a moderator:
@notaz: yep, that's a known issue (although it is not *really* an issue, the app. thread goes to sleep after a few spins). the kernel module could be improved in that regard. about the boot script: yea well, you are right, now that's the default firmware script :) that's great, is it not ?

p.s.: I mentioned that a few pages back. Support for select() would be nice, but for now I consider that rather nice to have because it does not add anything meaningful performance-wise. It is good dev-practice, won't argue with you about that.  (EDIT: feel free to add this if you think it's a must. It's all Open Source, after all. I've already added you as a contributing author to the "c64_tools" package)
 
Last edited by a moderator:
For Exophase (I am really reading your answers and I am glad you share your knowledge): Maybe don't use the dsp, use Neon for it, since it is a vector FPU and not Integer only like the dsp. I hope you, notaz and bsp are not annoyed by my strange, nooby ideas^^.

I am not sure if this is the right thread to talk about it but maybe someone (which means not me) can do something like this:

Look manually in a binary like UT or Half Life and look for good parallel functions with floating points. Like vertex transformation. I am not sure if it is the most expensive function but since you would have to do 2 x 16 operations for a vertex (positions and normals) and there are at least 1000 vertices, 32K floating point operations per frame are looking like the main bottleneck.

Patch the binaries, look for this functions and change the binary code. Handle this code with extra code in qemu. Make fmulp to cachedFmulp. Make cmp controllCmp.

Save cachedFmulp calls, until you controllCmp is true (so you notice the end of the loop). Then fire up the dsp and let it do all floating point operations asynchron (so the cpu can keep working). When a result from dsp is needed the cpu can stall and wait for the dsp to complete.

With this line kind of code, it would give some speed improvement:

transformVertices(); //when finished the dsp will start

handleSound(); //done in paralellel for the cpu

handleAI(); //done in paralellel for the cpu
passVerticesToGPU(); //the cpu has to wait until the dsp is ready

An example:


int main()
{
    struct Vertex vert[numberOfVertices];
    struct Matrix mat;
    int i;
    for (i = 0; i < numberOfVertices; i++)
    {
        vert[numberOfVertices].position[0] = mat.element[0][0] * vert[numberOfVertices].position[0];
    }
}
assembler (just a bit):


...
flds   (%rax)
fmulp  %st,%st(1)
mov    -0x10(%rbp),%rax
movslq %edx,%rdx
shl    $0x4,%rdx
add    %rdx,%rax
fstps  (%rax)
addl   $0x1,-0x4(%rbp)
mov    0xff(%rip),%eax        # 40065c <numberOfVertices>
cmp    %eax,-0x4(%rbp)
jl     400522 <main+0x6e>
...

Make fmulp to cachedFmulp. This way it can be saved, until all vertices are handled (notice it by cachedCmp).

Pseudo code for this:

Code:
bool saveCachedFmulp = false;
std::vector<OpCode> flopVector;

if (opcode == cachedFmulp)
{
 saveCachedFmulp = true;
flopVector.pushBack(opcode);
 
}

if (opcode == cachedCmp && saveCachedFmulp == true)
{
    if(getResult(opcode) == false) //end of loop
    {
       nonblockingDSPCall(flopVector);
    }
}

//let the cpu do other stuff while dsp is working and the result is not needed.
 
Binaries for games most likely won't have big arrays of vector multiplies to do the 3D work - they'll use the graphics card to do that work via a DirectX or OpenGL interface, I think.


I too would like to understand better the difference between the NEON lump of silicon and this DSP. In my mind, a DSP is something that implements a SIMD methodology for working on streams of data, and that's about as far as I understand them - and that's exactly how NEON is described. Like you say, NEON can handle floating point numbers (albeit at only 32-bit resolution, apparently) while the DSP is integer only, but other than that, what's the difference?
 
Back
Top