DSP Corner

Discussion in 'NEON / DSP' started by rohezal, Oct 14, 2013.

  1. rohezal

    rohezal Advanced Member

    Joined:
    Oct 18, 2009
    Messages:
    1,662
    Last edited by a moderator: Feb 6, 2016
    Tags:
  2. TrashyMG

    TrashyMG Sarcasm Dispenser Staff Member

    Joined:
    Jan 18, 2010
    Messages:
    10,532
    Seems reasonable to me.. Mr. Dragon would need to add it though.. 
     
  3. Askarus

    Askarus Hardcore Member

    Joined:
    Sep 28, 2011
    Messages:
    4,289
    Location:
    Germany
    No NEON corner  ;)  ?
     
  4. WizardStan

    WizardStan Mega GP Mania

    Joined:
    May 24, 2008
    Messages:
    16,697
    NEON is just a few extra instructions that need to be used in very specific scenarios. You can't say "here's my NEON MP3 decoder for anyone that wants to use it" like you could with the DSP. Well, you could write a NEON based MP3 library I guess, but it wouldn't have anywhere near the same effect as writing it entirely for the DSP. :p
     
  5. rohezal

    rohezal Advanced Member

    Joined:
    Oct 18, 2009
    Messages:
    1,662
    The dsp would offer certain functions which can be offloaded to it (including your own functions). Like a second cpu with a collection of predefined functions and an interface to use it.

    This is pretty great and if it would be easy to use and good documented, more people would use it. This would increase the performance of all Pandora models.
     
    Last edited by a moderator: Oct 14, 2013
  6. bsp

    bsp Active Member

    Joined:
    Sep 5, 2013
    Messages:
    314
    First of all, thank you, rohezal, for this reminder thread and thank you, EvilDragon, for creating this sub-forum!

    Interesting to see that many DSP related threads popping up all of a sudden (they were there all the time, of course but I did not know about them) :)

    I read a few of them and took a few minutes to summarize the DSP situation on the Pandora:

     regarding DSPBridge:

    • developed by Nokia and TI
    • ARM side source uses GPL license, DSP side is a closed source binary blob 
    • features on-demand shared memory allocation (no need to statically reserve memory at boot time
    • features a dynamic ELF DSP code loader 
    • power management (but no auto suspend/resume
    • DSP can be shared my multiple ARM processes 
    • [uncertain] API can allocate arbitrary memory regions (like malloc() / free()) ? 
    • relatively high messaging latency (~0.7 ms) reported by devs who tried it on the Pandora 
    • no access to DSP SRAM on ARM side 
    • semi-abandoned project (who maintains DSP-side code?)
    • no Pandora application using it (except for a proof-of-concept port of TI's gstreamer DSP, see http://repo.openpandora.org/?page=detail&app=gst_dsp_pkg )
    • does not seem to work in current firmware, anyway (not on my 1GHz Pandora, at least (mailbox error during startup)) 
      EDIT: kernel module loads and starts DSP but produces scary backtrace in klog due to DSP "in-band error at address 0" (segmentation fault?) (looks similar to http://e2e.ti.com/support/dsp/omap_applications_processors/f/447/t/194647.aspx)
      According to this http://www.spinics.net/lists/linux-omap/msg61246.html it's a bug in the DSP firmware that noone can fix since it is closed source.
    • support via TI forum? website/wiki is heavily outdated and seems incomplete.

     regarding DSPLink:

    • developed by TI 
    • ARM side source uses GPL license, DSP-side source uses 4-clause/original BSD license 
    • requires static memory reservation at boot time ("RAM cut for DSP"
    • loads one statically linked COFF DSP image (.out file) 
    • [uncertain] only one process can use it (on other systems I worked on there used to be a userspace "dsplink" process which acted as a proxy so multiple processes could share the DSP. very high message latencies (~2..3 ms), though) 
    • no power management (constant power drain even if DSP is not actually used
    • no access to DSP SRAM on ARM side 
    • API can only allocate memory from pre-defined (at DSP boot time) pools (e.g. 4*64k, 16*256k, ..
    • no Pandora application using it, although there once was a proof-of-concept videodecoder demo for older 2.6.x kernels 
    • in my (and others) experience not easy to make it build and work. not really easy to use 
    • does not seem to work in current firmware, anyway (not on my 1GHz Pandora, at least (kernel crash in PROC_setup()
    • no support (only for paying customers)

     regarding c64_tools:

    • community effort 
    • ARM side source uses GPL license, DSP-side source uses MIT license 
    • features on-demand shared memory allocation (no need to statically reserve memory at boot time
    • loads up to five statically linked COFF DSP images (.out files) (one core image + up to 4 overlay images
    • power management (including auto suspend/resume. when the DSP is not used it will consume zero power
    • DSP can be shared by multiple ARM processes 
    • API (in soon-to-be-released update) can allocate arbitrary memory regions (like malloc() / free()) 
    • very low messaging latency (~0.04 ms for IRQ driven messages, ~0.002 ms in polling mode)
    • userspace access to second half (24 KBytes) of DSP L1DSRAM
    • relatively new project 
    • no Pandora application using it, although there are a couple of simple examples / demos 
    • works with upcoming SuperZaxxon firmware resp. requires an updated kernel (a binary is available for d/l
    • voluntary support (via this forum or e-mail)
     
    Last edited by a moderator: Oct 14, 2013
    gunrock and rohezal like this.
  7. notaz

    notaz Certified Guru

    Joined:
    Aug 23, 2005
    Messages:
    4,913
    Location:
    Lithuania
    http://repo.openpandora.org/?page=detail&app=gst_dsp_pkg does, but it insists of using it's own kernel ("your kernel does not support the DSP!!!").

    Works for me, run "sudo /usr/pandora/scripts/op_dsp.sh start" on clean boot, you'll get some scary backtraces in dmesg but it will load. A version of gstreamer from mentioned .pnd can then play videos, which often play worse than with ARM decoding, but sometimes a bit better.

    The kernel side seems to be still maintained somewhat:

    https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/log/drivers/staging/tidspbridge
     
    Last edited by a moderator: Oct 14, 2013
  8. rohezal

    rohezal Advanced Member

    Joined:
    Oct 18, 2009
    Messages:
    1,662
    I think the key to success are easy to use predefined functions.

    Something like this:

    #include <c64_dsp.h>

    const int veryBig = 1<<20;

    int bigArray[veryBig];

    void main()

    {

       fillArrayWithRandomStufff();

       int max = __DSP64_GetMaximum(bigArray,veryBig);

       //do other stuff like playSound();

       waitForDsp();

       printf(max);

    }
     
    Last edited by a moderator: Oct 14, 2013
  9. bsp

    bsp Active Member

    Joined:
    Sep 5, 2013
    Messages:
    314
    I tried that before. I also tried booting with all the available (precompiled) kernels. I even reflashed the firmware (for a different reason but after I did I retried dspbridge as well). I kept the log file (see attachment). Retried again just now (after clean reboot), this time it said "proc_start: DSP in running state" (for the first time!) then immediately after that I got a kernel crash (see attachment).

    @rohezal: that code will _never_ work :) (waitForDsp() would need to be done in the GetMaximum() function) but I know what you mean

    dspbridge_crash-14Oct2013.txt

    dspbridge_test-02Oct2013.txt
     

    Attached Files:

  10. rohezal

    rohezal Advanced Member

    Joined:
    Oct 18, 2009
    Messages:
    1,662
    Maybe this is the wrong thread, but how do you know, that the dsp is done working in this example? Or would the dsp block the main cpu until it is done?
     
    Last edited by a moderator: Oct 14, 2013
  11. bsp

    bsp Active Member

    Joined:
    Sep 5, 2013
    Messages:
    314
    hey, it's your thread :) the title is generic enough for this to contain "random" DSP talk, I guess.

    to make your example work, you need to do sth. likes this:


    #include <stdio.h>
    #include <inc_libc64.h>
    #include <components/arrayutils/arrayutils.h>

    /* let's assume there's an "ARRAYUTILS" component and it has a "GETMAXIMUM" function */

    const unsigned int veryBig = 1<<20;

    dsp_mem_region_t shm;
    dsp_component_id_t compid_arrayutils;

    int *bigArray;

    /* Add missing fxns here (fillArrayWithRandomStufff()) */

    static void __DSP64_GetMaximum_send(int *_bufAddrPhys, unsigned int _numInts) {
    c64_msg_t req;
    DSP_MSG_INIT(&req,
    compid_arrayutils, ARRAYUTILS_CMD_GETMAXIMUM,
    _bufAddrPhys, _numInts
    );

    /* Write back ARM caches so DSP sees actual data */
    (void) dsp_cache_wb(_bufAddrPhys, _numInts * sizeof(int));

    /* Send request to DSP */
    (void) dsp_rpc_send(&req);
    }

    static int __DSP64_GetMaximum_recv(void) {
    c64_msg_t reply;
    (void) dsp_rpc_recv(&reply);
    /* assumes that the 1st of the 2 retvals contains the error code and the
    2nd one the actual result value */
    return (int) reply.data[1].ret;
    }

    int main(int,char**) {

    /* Open client connection to c64.ko kernel module */
    (void) dsp_open();

    /* Alloc. DSP<>GPP shared memory (should check return value) */
    (void) dsp_shm_init(veryBig * sizeof(int));

    /* Query physical (DSP-side) and virtual (GPP-side) addresses and size */
    shm = dsp_shm_get();

    /* Load arrayutils component (DSP overlay image) */
    (void) dsp_component_load(NULL /*cwd*/, COMPONENT_NAME_ARRAYUTILS, &compid_arrayutils);

    bigArray = (int*) shm.virt_addr;

    fillArrayWithRandomStufff();

    /* Send request to DSP and return immediately */
    __DSP64_GetMaximum_send(shm.phys_addr /* bigArray */, veryBig);

    //do other stuff like playSound();

    /* Wait for DSP and pick up result */
    int max = __DSP64_GetMaximum_recv();

    printf("max=%d\n", max);

    /* Unload DSP overlay, free shared memory, disconnect */
    dsp_close();
    return 0;
    }

    this is *almost* actual code (did not try, it definitely misses error checking).
     
     
    Last edited by a moderator: Oct 14, 2013
    rohezal likes this.
  12. rohezal

    rohezal Advanced Member

    Joined:
    Oct 18, 2009
    Messages:
    1,662
    Thank you :) .

    Very interesting, the dsp __DSP64_GetMaximum() function is not blocking right? So

    //do other stuff like playSound();

    can work while the dsp is busy, right? What are the members of the c64_msg_t struct? Why does it have 2 return values? I think I ask for to much, but a nice doxygen site online (so you can google c64_msg_t) would be sweet :) .
     
    Last edited by a moderator: Oct 14, 2013
  13. bsp

    bsp Active Member

    Joined:
    Sep 5, 2013
    Messages:
    314
    the c64_msg_t struct is defined in c64_tools/include/msg.h

    it has 2 return values since each function can have two (scalar) arguments and the arg/return fields are in a union.

    there will be docs other than the source code..have to overcome laziness first :)
     
  14. crow_riot

    crow_riot Well-Known Member

    Joined:
    Sep 21, 2009
    Messages:
    1,763
    Location:
    .at
    thanks for th code above. source for the dsp side of that mini sample would be good to see :)
     
  15. bsp

    bsp Active Member

    Joined:
    Sep 5, 2013
    Messages:
    314
    /* in dsp/components/arrayutils/arrayutils.h: */

    #define COMPONENT_NAME_ARRAYUTILS "arrayutils"

    #define ARRAYUTILS_CMD_GETMAXIMUM (1)

    #define ARRAYUTILS_ERR_OK (0)
    #define ARRAYUTILS_ERR_CMD (1)

    #ifndef MLB_COMPONENT_GPP
    S_EXTERN dsp_component_t component_arrayutils;
    #endif /* MLB_COMPONENT_GPP */


    /* in dsp/components/arrayutils/arrayutils.c: */

    #define SYSCALLS_C defined
    #include <libc64_dsp/include/inc_overlay.h>
    #include "arrayutils.h"

    static int loc_getMaximum(int *_arr, sU32 _numInts) {
    int ret = INT_MIN;
    sU32 i;

    /* Invalidate caches so DSP sees actual data */
    syscalls.cache_inv(_arr, _numInts * sizeof(int), S_TRUE/*wait*/);

    for(i=0; i<_numInts; i++)
    {
    int c = _arr;

    if(c > ret)
    {
    ret = c;
    }
    }

    return ret;
    }

    static sU32 loc_exec(dsp_component_cmd_t _cmd,
    sU32 _arg1, sU32 _arg2,
    sU32 *_ret1, sU32 *_ret2
    ) {
    sU32 ret;

    switch(_cmd)
    {
    default:
    /* Failed: illegal command id */
    *_ret1 = ret = ARRAYUTILS_ERR_ILLCMD;
    break;

    case ARRAYUTILS_CMD_GETMAXIMUM:
    *(int*)_ret2 = loc_getMaximum((int*)_arg1 /*buf*/, _arg2 /*numInts*/);

    /* Succeeded */
    *_ret1 = ret = ARRAYUTILS_ERR_OK;
    break;
    }

    return ret;
    }

    #pragma DATA_SECTION(component_arrayutils, ".sec_com"); /* link to abs. addr. */
    dsp_component_t component_arrayutils = {
    0, /* component id, auto-assigned when c. is registered */

    /* fxns: */
    {
    NULL, /* init */
    &loc_exec, /* exec IRQ driven RPC */
    NULL, /* exec fastcall RPC */
    NULL /* exit */
    },

    COMPONENT_NAME_ARRAYUTILS
    };

    DSP_COMPONENT_MAIN

    this is very similar to the "demo_checksum" example which is included with the c64_tools tar.gz

    I also have to add that it is better/faster to use the first return value for error codes and the second one for the actual return value.

    The error code returned by loc_exec() is an "errno" style error code that is a bit more expensive to read and only exists once, not per process. Maybe I'll change that later on but that does not have high priority.
     
    Last edited by a moderator: Oct 14, 2013
    rohezal likes this.
  16. notaz

    notaz Certified Guru

    Joined:
    Aug 23, 2005
    Messages:
    4,913
    Location:
    Lithuania
    That's not a crash, it's just the scary warning I was talking about (look for WARNING: and not BUG: or OOPS: which would be fatal). The system is fully functional after that.
     
    Last edited by a moderator: Oct 14, 2013
  17. bsp

    bsp Active Member

    Joined:
    Sep 5, 2013
    Messages:
    314
    ah ok. I just saw the "inband error" message and the scary backtrace. I'll update the message/summary above.
     
  18. rohezal

    rohezal Advanced Member

    Joined:
    Oct 18, 2009
    Messages:
    1,662
    If we would have a header file with functions like

    static void __DSP64_GetMaximum_send(int *_bufAddrPhys, unsigned int _numInts);
    static int __DSP64_GetMaximum_recv(void) ;

    I am sure a lot of people would use the dsp, since it is very easy :) . Like std::max(std::vector<int>) you can type __DSP64_GetMaximum_send(array,size) which is very easy. Btw. why did you make write the static in front of the functions? Is it for the return value (functions are always static in C as far as I know)? Why would you need a static return value?

    Maybe other useful stuff (like minimum, [merge?] sort, average) will be written some day.
     
    Last edited by a moderator: Oct 14, 2013
  19. bsp

    bsp Active Member

    Joined:
    Sep 5, 2013
    Messages:
    314
    I wrote static since I wanted a function that is local to the current source module. That's how C works :)

    Please do not forget that calling the DSP comes with a certain price / overhead. It makes no sense to use the DSP to e.g. determine the maximum number in an array of say 64 elements.

    EDIT: You can call DSP functions thousands of times per second but for a computer this is slow. Ideally you prepare a list of jobs for the DSP, then let it process these jobs all at once. Just like you would rather send a longer letter to someone instead of sending one letter for each sentence of the message (that was not meant to sound condescending, just an example to clarify this)

    The most useful application of the DSP are higher level jobs, like e.g. emulating a soundchip / synthesizing music, decoding a video or audio (mp3) frame, or matrix transforming a significant number of vectors.

    You can use it for relatively small processing jobs but you really have to know what you are doing in that case. I guess only advanced games or emulator devs will use that feature ("fastcall"), if at all.
     
    Last edited by a moderator: Oct 14, 2013
  20. rohezal

    rohezal Advanced Member

    Joined:
    Oct 18, 2009
    Messages:
    1,662
    I think my post here is stupid. 1000 integer elements would be quite fast on the main cpu (with one cycle per isLowerThen Op, without memory access). Around 0.001ms for lowerThenOps, some time for the loop and the incrementation of the counter variable.  But probably less then 0.01ms for all of this. Calling the DSP alone takes 0.04ms :( . Thinking about what numbers for what algorithm you can think of, when it is useful to use the dsp.

    In this case of finding the min / max in maybe 1.000.000 numbers, it would be worth the overhead (maybe 10 ms vs 0.04 ms overhead).

    Sorting is more expensive then minima / maxima search, but not much more (N*logN).

    Filter an image (even 128x128 pixels) with average would be something nice to do.

    Block matching (4x4 pixels - 4x4) probably too.

    Is median filtering possible on a DSP (non linear operation)?

    I am thinking about the use for games. Like a game with 1024 units on the field and the AI needs to know which unit (index) has the least HP or would do most damage.

    would need a struct like this

    struct units

    {

     int hitpoints[1024];

     int damage[1024];

     int armor[1024];

     float posX[1024];

     float posY[1024];

     Image* sprite[1024];

    };

    but hey if the game is optimised for the dsp, who knows? But the real world use, would not be very big, I think I see this now :( .
     
    Last edited by a moderator: Oct 15, 2013

Share This Page

Loading...