[announce] c64_tools (DSP loader and IPC)


OK I wrote my first DSP component today, and doing it felt a bit.. uncomfortable.
:) that's normal

First thing, your build system doesn't allow out-of-tree (out of c64_tool folder) components, as the linker scripts (pre.cmd, link_area*.cmd, post.cmd) are supplied with relative path
ok, that literally took two minutes to fix (see changelog below).

Next this black magic

#pragma DATA_SECTION(component_test_dsp, ".sec_com");


..could be be hidden away in DSP_COMPONENT_MAIN by passing component structure to the macro like DSP_COMPONENT_MAIN(component_test_dsp). Or maybe it's not even needed, as everything seems to work without that pragma?
How is that supposed to work ? DSP_COMPONENT_MAIN is a macro and you cannot #define things or use #pragma within macros in C !?


The #pragma is definitely needed because it tells the linker to place the component structure at a very specific address which varies depending on the overlay number (area2_1..2_4, area3).

Take a look at libc64_dsp/src/mlb.c:loc_mlb_overlay_register() - the section index (overlay#) is used to determine the address of the component structure. It needs to be located at very specific addresses.

dsp_component_t could also move component_id to the bottom of the structure so that /* component id, assigned in mlb_component_register() */ doesn't have to be specified.
You're completely right.

For some reason I thought that incomplete struct initialization was bad practice (although I already did that anyway w/o noticing) but the C standard clearly states that fields that are not initialized explicitely will be set to 0.


so, good idea, thank you!


Originally I did not want to upload a new snapshot today but since you're on to something there, you can probably use it:

+ add inc_libc64_mini.h include helper (minimal dependencies, e.g. no log/osal)


+ add c64_minimal example


+ do not build SDL tests by default


+ add eDMA3/TPCC register defines to dm3730.h


+ add dsp_virt_to_phys() API call (untested)


+ add dsp_phys_to_virt() API call (untested)


+ fix DSP build_area*.mk scripts to locate linker scripts relative to $(C64_TOOLS_DSP_ROOT)


+ add DSP out-of-tree build example (dsp_oot/ directory, will be removed in next release)


+ move component_id field of dsp_component_t so its initialization can be skipped


+ release http://tkscript.de/c64_tools/c64_tools-20Oct2013_snapshot.tar.gz

EDIT: http://tkscript.de/c64_tools/c64_tools-20Oct2013_snapshot_b.tar.gz fixes a stupid typo in the virt_to_phys/phys_to_virt functions. still untested (but should work).
 
Last edited by a moderator:
Next this black magic


#pragma DATA_SECTION(component_test_dsp, ".sec_com");


..could be be hidden away in DSP_COMPONENT_MAIN by passing component structure to the macro like DSP_COMPONENT_MAIN(component_test_dsp). Or maybe it's not even needed, as everything seems to work without that pragma?
How is that supposed to work ? DSP_COMPONENT_MAIN is a macro and you cannot #define things or use #pragma within macros in C !?
You are right of course, I'm too used to doing sections in asm.S files, and you can use macros there so I assumed without thinking, oops!

The #pragma is definitely needed because it tells the linker to place the component structure at a very specific address which varies depending on the overlay number (area2_1..2_4, area3).
Hmm, I guess it works for me because I don't have anything else in my .data section and dsp_component_t still ends being first.

Originally I did not want to upload a new snapshot today but since you're on to something there, you can probably use it:
Hmm it seems to break my today's setup:

Edit: rebooted and it's all good again, so perhaps I had some memory corruption..


[...] coff_load_overlay: text=0x00000440 data=0x00000054 bss=0x00001040
[---] loc_overlay_component_register_end: failed to register section 4 main component. ret=0
[---] dsp_component_load: failed to register overlay main component (img="secret_project_area3.out"). ret=6
compid: ret=6, id=0
dsp_rpc: ret=0

Note that dsp_rpc() still worked without error after I ignored dsp_component_load() return, I guess I ended up sending command to core or something?

I have a feature request: printf to circular buffer on the DSP that could be later retrieved and printed with a call from GPP. Perhaps reserve 16kB or so from initial 8MB for it. All DSP crashes/faults could be logged there too.


Curiously using printf currently links (with warnings), but libc64 segfaults while loading such .out file.


We also have to do something to catch NULL pointer accesses on DSP, I've already managed to do some trashing around address 0 by passing args incorrectly.. OMAP3 has GPMC (aka NAND) controller there, so invalid accesses have real potential to destroy user's data.

Edit2: why isn't -O specified to cl6x? It seems to give good performance improvement (2x for int-like copy loop).
 
Last edited by a moderator:
With regards to sections, how does this work out for you:

Code:
mac:pandora-dev scraft$ cat main.cpp

/* Section name for components. */
#define DSP_SECTION_NAME ".mambo"

/* Puts component into correct segment and does other stuff. */
#define DSP_COMPONENT_MAIN( _Name )     \
        extern int _Name __attribute__((section( DSP_SECTION_NAME )))

/* Create instance of data */
int g_test = 0x12345678;

/* Create component, which also puts instance into correct section. */
DSP_COMPONENT_MAIN( g_test );

int main( )
{
        return g_test;
}

mac:pandora-dev scraft$ arm-2011.09/bin/arm-none-linux-gnueabi-g++ --sysroot=arm-2011.09/ main.cpp

mac:pandora-dev scraft$ arm-2011.09/bin/arm-none-linux-gnueabi-readelf -S a.out | grep "\.mambo"

  [22] .mambo            PROGBITS        00010568 000568 000004 00  WA  0   0  4
 
Last edited by a moderator:
^^ That's a good idea. (http://stackoverflow.com/a/3385536 ?). I'll look into that and add that in the next update. Thanks for the review!
There are various ways to do static asserts, I think the ones you linked to only works inside the body of the function. The example I gave works at global scope too, so is probably preferable. With the more recent standards there is static assert support by the compiler, but we are yonks away from the later standards to be usable en masse.
 
The #pragma is definitely needed because it tells the linker to place the component structure at a very specific address which varies depending on the overlay number (area2_1..2_4, area3).
Hmm, I guess it works for me because I don't have anything else in my .data section and dsp_component_t still ends being first.
that's probably it.

Note that dsp_rpc() still worked without error after I ignored dsp_component_load() return, I guess I ended up sending command to core or something?
If you used comp_id == 0, then yes, you called some core component function ;)

I should probably return ~0, although (needless to say I hope), you should check the return values of the dsp_*() function calls and not proceed in case such a fatal error occured.

If you used a non-existing comp_id then nothing would have happened. Looking at the code I should probably set the global DSP errno in that case although this is a consequential error resulting from the missing error check.

I have a feature request: printf to circular buffer on the DSP that could be later retrieved and printed with a call from GPP. Perhaps reserve 16kB or so from initial 8MB for it. All DSP crashes/faults could be logged there too.
Actually the thought of implementing that crossed my mind. When I first started coding on the DSP, I also immediately looked for a printf resp. implemented a ringbuffer printf. However, I did not really use it that much because it did not help much with debugging any streaming algorithms (+ we had a hardware debugger). I see what I can do, it's rather easy to implement. Instead of using CMA mem (that's what you meant by "the initial 8MB " ? The DSP codemem is just 4MB, right ?) I will link the debug ringbuffer to a fixed memory location and just mmap() that on the GPP side. 16kb sounds reasonable.

We also have to do something to catch NULL pointer accesses on DSP, I've already managed to do some trashing around address 0 by passing args incorrectly.. OMAP3 has GPMC (aka NAND) controller there, so invalid accesses have real potential to destroy user's data.
At some point we'll have to enable the MMU, I'm aware of that. Although this is not really the point: Isn't the GPMC located at 0x6e000000 ? I also thought that NAND writes could not be triggered by accidental writes but required a deliberate programming sequence that is unlikely to happen by mistake ?

Edit2: why isn't -O specified to cl6x? It seems to give good performance improvement (2x for int-like copy loop).
I assume you mean "why is the core not compiled with -O" ? Because at least the demo_fractal example is compiled with full optimizations (-O3 ...)

If you take a look at a component's makefile you will see these lines:


#OPTFLAGS+= $(OPTFLAGS_NONE)
OPTFLAGS+= $(OPTFLAGS_SPEED)
#OPTFLAGS+= $(OPTFLAGS_SIZE)
Just pick OPTFLAGS_SPEED and you will get software pipelined loops / full compiler optimizations.

The reason why the core is compiled with -O0 is that I've seen so many "strange" things happen when it's compiled with optimizations. It could very well be that these things happened due to different reasons and that it is now safe to compile with -O3 but I have not retried that. I also would not expect any significant performance increase since the RPC call frequency is limited by the interrupt latency, or in case of fastcalls, by the L1DSRAM access speed (on the GPP side).

With regards to sections, how does this work out for you:


#define DSP_COMPONENT_MAIN( _Name ) \
extern int _Name __attribute__((section( DSP_SECTION_NAME )))
Remember that the DSP code is not compiled with GCC. The section attribute is not available in cl6x.

^^ That's a good idea. (http://stackoverflow.com/a/3385536 ?). I'll look into that and add that in the next update. Thanks for the review!
There are various ways to do static asserts, I think the ones you linked to only works inside the body of the function
I did not mean to link to that specific post but rather the whole topic (http://stackoverflow.com/questions/3385515/static-assert-in-c) in general, dunno how that happened.
 
Instead of using CMA mem (that's what you meant by "the initial 8MB " ? The DSP codemem is just 4MB, right ?) I will link the debug ringbuffer to a fixed memory location and just mmap() that on the GPP side. 16kb sounds reasonable.
Yeah I meant the CMA mem, but your suggestion is good too.

We also have to do something to catch NULL pointer accesses on DSP, I've already managed to do some trashing around address 0 by passing args incorrectly.. OMAP3 has GPMC (aka NAND) controller there, so invalid accesses have real potential to destroy user's data.
At some point we'll have to enable the MMU, I'm aware of that. Although this is not really the point: Isn't the GPMC located at 0x6e000000 ? I also thought that NAND writes could not be triggered by accidental writes but required a deliberate programming sequence that is unlikely to happen by mistake ?
I've looked at the manual again and it turns out the DSP has it's own peripherals mapped at 0..0x10ffffff, not the main L3 bus, and of that 0..0x7dffff is marked as reserved, so maybe no harm done.


It's really strange though, EDMA has even different view of the memory even if it's sitting on the same bus as DSP, it sees video accelerator where DSP sees it's caches and stuff. And for DSP to access the video stuff, it has to use special instructions which are not part of stock C64x? And there is also IDMA which sees who knows what, and ARM9 on yet another bus? How much more complicated could they make that thing?

If you take a look at a component's makefile you will see these lines:


#OPTFLAGS+= $(OPTFLAGS_NONE)
OPTFLAGS+= $(OPTFLAGS_SPEED)
#OPTFLAGS+= $(OPTFLAGS_SIZE)
Just pick OPTFLAGS_SPEED and you will get software pipelined loops / full compiler optimizations.
Ah, I somehow failed to copy that to my own makefile. O2 seems to give better performance than O3 in that test though.
 
It's really strange though, EDMA has even different view of the memory even if it's sitting on the same bus as DSP, it sees video accelerator where DSP sees it's caches and stuff. And for DSP to access the video stuff, it has to use special instructions which are not part of stock C64x? And there is also IDMA which sees who knows what, and ARM9 on yet another bus? How much more complicated could they make that thing?
EDMA really uses different addresses than the DSP ??!

I'd be surprised if this were true -- at least on the previous TI boards I worked with eDMA used the same address view as the DSP itself.

Originally I wanted to work on the EDMA driver this evening but then decided to implement the logging first (we do not have a HW debugger here so this might come in handy)

I guess I'll find out tomorrow.

Regarding the video accelerator: I have not used that one but I think I too saw some bits in the documentation that talked about special instructions :/

Regarding IDMA: That should use the same addresses as the DSP. I have not used IDMA myself but it's meant for fast DSP internal memory transfers.

And hell yeah, it's quite complicated, at least compared to the old homecomputers ;)

Now for the good news / today's update:

+ add DSP syscall cache_wb() (warning: syscall shift, please recompile all components)


+ add DSP syscall puts()


+ add DSP syscall printf()


+ add DSP syscall vprintf()

+ add DSP_LOGBUF_SIZE, DSP_LOGBUF_BASE_GPP to dsp_config.h

+ add DSP log ringbuffer

+ add "TEST_LOGBUF" DSP example component

+ support for DSP logbuf in kmod/dev.c:fops__mmap


+ sync with DSP logbuf in dsp_open()


+ add dsp_logbuf_print()


+ add TC_LOGBUF testcase to c64_tc


+ test logbuf with DSP suspend/resume


+ add TC_LOGBUF_MANY testcase to c64_tc (test ringbuffer wrap-around)

+ release http://tkscript.de/c64_tools/c64_tools-21Oct2013_snapshot.tar.gz
 
Last edited by a moderator:
I tried compiling this on a Ubuntu Virtual Machine, using a tool chain built from the script in this thread http://boards.openpandora.org/index.php/topic/7147-crosscompiler-toolchain-based-on-openpandoraorg-ipks/ however the linker appears to crash sadly:


ubuntu@ubuntu-VirtualBox:~/Downloads/c64_tools$ make -f makefile.linux libc64_clean CROSS_COMPILE=~/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi- CROSS_ROOT=~/pandora-dev/arm-2011.09
make -C libc64 -f makefile.linux clean
make[1]: Entering directory `/home/ubuntu/Downloads/c64_tools/libc64'
rm -f dsp.o ../src/log.o ../src/coff.o ../src/coff_overlay.o ../src/arch/dm3730/dsp_config.o ../src/osal/osal.o ../src/osal/linux/osal_linux.o libc64.so libc64.a
make[1]: Leaving directory `/home/ubuntu/Downloads/c64_tools/libc64'
ubuntu@ubuntu-VirtualBox:~/Downloads/c64_tools$ make -f makefile.linux libc64 CROSS_COMPILE=~/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi- CROSS_ROOT=~/pandora-dev/arm-2011.09
make: Nothing to be done for `libc64'.
ubuntu@ubuntu-VirtualBox:~/Downloads/c64_tools$ make -f makefile.linux tests_clean CROSS_COMPILE=~/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi- CROSS_ROOT=~/pandora-dev/arm-2011.09
make -C tests -f makefile.linux clean
make[1]: Entering directory `/home/ubuntu/Downloads/c64_tools/tests'
rm -f c64_tc.o omapfb.o c64_fractal.o sdl_test.o c64_tc c64_fractal sdl_test reg_read
make[1]: Leaving directory `/home/ubuntu/Downloads/c64_tools/tests'
ubuntu@ubuntu-VirtualBox:~/Downloads/c64_tools$ make -f makefile.linux tests CROSS_COMPILE=~/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi- CROSS_ROOT=~/pandora-dev/arm-2011.09
make -f makefile.linux tests_clean && make -f makefile.linux tests_bin
make[1]: Entering directory `/home/ubuntu/Downloads/c64_tools'
make -C tests -f makefile.linux clean
make[2]: Entering directory `/home/ubuntu/Downloads/c64_tools/tests'
rm -f c64_tc.o omapfb.o c64_fractal.o sdl_test.o c64_tc c64_fractal sdl_test reg_read
make[2]: Leaving directory `/home/ubuntu/Downloads/c64_tools/tests'
make[1]: Leaving directory `/home/ubuntu/Downloads/c64_tools'
make[1]: Entering directory `/home/ubuntu/Downloads/c64_tools'
make -C tests -f makefile.linux bin
make[2]: Entering directory `/home/ubuntu/Downloads/c64_tools/tests'
make -C ../libc64 -f makefile.linux bin
make[3]: Entering directory `/home/ubuntu/Downloads/c64_tools/libc64'
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O2 -DHAVE_OS_LINUX -c dsp.c -o dsp.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O2 -DHAVE_OS_LINUX -c ../src/log.c -o ../src/log.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O2 -DHAVE_OS_LINUX -c ../src/coff.c -o ../src/coff.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O2 -DHAVE_OS_LINUX -c ../src/coff_overlay.c -o ../src/coff_overlay.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O2 -DHAVE_OS_LINUX -c ../src/arch/dm3730/dsp_config.c -o ../src/arch/dm3730/dsp_config.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O2 -DHAVE_OS_LINUX -c ../src/osal/osal.c -o ../src/osal/osal.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O2 -DHAVE_OS_LINUX -c ../src/osal/linux/osal_linux.c -o ../src/osal/linux/osal_linux.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -shared -o "libc64.so" -Wl,-soname,libc64.so -L/home/ubuntu/pandora-dev/arm-2011.09/usr/lib dsp.o ../src/log.o ../src/coff.o ../src/coff_overlay.o ../src/arch/dm3730/dsp_config.o ../src/osal/osal.o ../src/osal/linux/osal_linux.o -lpthread
rm -f libc64.a
ar r libc64.a dsp.o ../src/log.o ../src/coff.o ../src/coff_overlay.o ../src/arch/dm3730/dsp_config.o ../src/osal/osal.o ../src/osal/linux/osal_linux.o
ar: creating libc64.a
make[3]: Leaving directory `/home/ubuntu/Downloads/c64_tools/libc64'
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O3 -pipe -march=armv7-a -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -I../dsp -DHAVE_OS_LINUX -c c64_tc.c -o c64_tc.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -o c64_tc -Wl,-R./ c64_tc.o -L../libc64 -lc64 -L/home/ubuntu/pandora-dev/arm-2011.09/usr/lib
/home/ubuntu/pandora-dev/arm-2011.09/bin/../lib/gcc/arm-none-linux-gnueabi/4.6.1/../../../../arm-none-linux-gnueabi/bin/ld: BFD (Sourcery CodeBench Lite 2011.09-70) 2.21.53.20110905 assertion fail /scratch/jwlemke/2011.09-arm-linux-eabi-lite/obj/binutils-src-2011.09-70-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:11463
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O3 -pipe -march=armv7-a -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -I../dsp -DHAVE_OS_LINUX -c omapfb.c -o omapfb.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O3 -pipe -march=armv7-a -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -I../dsp -DHAVE_OS_LINUX -c c64_fractal.c -o c64_fractal.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -o c64_fractal -Wl,-R./ omapfb.o c64_fractal.o -L../libc64 -lc64 -L/home/ubuntu/pandora-dev/arm-2011.09/usr/lib -lm -lSDL -lts
/home/ubuntu/pandora-dev/arm-2011.09/bin/../lib/gcc/arm-none-linux-gnueabi/4.6.1/../../../../arm-none-linux-gnueabi/bin/ld: BFD (Sourcery CodeBench Lite 2011.09-70) 2.21.53.20110905 assertion fail /scratch/jwlemke/2011.09-arm-linux-eabi-lite/obj/binutils-src-2011.09-70-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:11463
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -Wall -I/home/ubuntu/pandora-dev/arm-2011.09/usr/include -O3 -pipe -march=armv7-a -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -I../dsp -DHAVE_OS_LINUX -c sdl_test.c -o sdl_test.o
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -o sdl_test -Wl,-R./ sdl_test.o -L../libc64 -lc64 -L/home/ubuntu/pandora-dev/arm-2011.09/usr/lib -lm -lSDL -lts
/home/ubuntu/pandora-dev/arm-2011.09/bin/../lib/gcc/arm-none-linux-gnueabi/4.6.1/../../../../arm-none-linux-gnueabi/bin/ld: BFD (Sourcery CodeBench Lite 2011.09-70) 2.21.53.20110905 assertion fail /scratch/jwlemke/2011.09-arm-linux-eabi-lite/obj/binutils-src-2011.09-70-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:11463
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -o reg_read -Wl,-R./ reg_read.o -L../libc64 -lc64 -L/home/ubuntu/pandora-dev/arm-2011.09/usr/lib
/home/ubuntu/pandora-dev/arm-2011.09/bin/../lib/gcc/arm-none-linux-gnueabi/4.6.1/../../../../arm-none-linux-gnueabi/bin/ld: BFD (Sourcery CodeBench Lite 2011.09-70) 2.21.53.20110905 assertion fail /scratch/jwlemke/2011.09-arm-linux-eabi-lite/obj/binutils-src-2011.09-70-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:11463
/home/ubuntu/pandora-dev/arm-2011.09/bin/arm-none-linux-gnueabi-gcc -o reg_write -Wl,-R./ reg_write.o -L../libc64 -lc64 -L/home/ubuntu/pandora-dev/arm-2011.09/usr/lib
/home/ubuntu/pandora-dev/arm-2011.09/bin/../lib/gcc/arm-none-linux-gnueabi/4.6.1/../../../../arm-none-linux-gnueabi/bin/ld: BFD (Sourcery CodeBench Lite 2011.09-70) 2.21.53.20110905 assertion fail /scratch/jwlemke/2011.09-arm-linux-eabi-lite/obj/binutils-src-2011.09-70-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:11463
make[2]: Leaving directory `/home/ubuntu/Downloads/c64_tools/tests'
make[1]: Leaving directory `/home/ubuntu/Downloads/c64_tools'

Is this because I am using the wrong tool chain and instead need to be using the TI one for the DSP? I am sure there was a thread around here with information on how to build but I can't seem to find it at the moment for looking..
 
Last edited by a moderator:
however the linker appears to crash sadly:
I presume you are referring to these messages


[..] BFD (Sourcery CodeBench Lite 2011.09-70) 2.21.53.20110905 assertion fail /scratch/jwlemke/2011.09-arm-linux-eabi-lite/obj/binutils-src-2011.09-70-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:11463
don't worry, I get them too and have not seen any runtime/crash issues because of them.

Is this because I am using the wrong tool chain and instead need to be using the TI one for the DSP?
nope since you are compiling only the ARM/GPP side of things.

To build the DSP side you have to download the TI compiler + libs (see DSP corner thread, 2nd page) first, then go to the "dsp/" folder, edit "setenv.sh", run it (". setenv.sh"), then rebuild with "m clean; m bin".

Last but not least, you may want to use a more recent release of c64_tools, e.g. the one linked to two posts above.

(your log output tells me that you are using an older release)
 
Thanks for printf, seems to work well. I really hate those <BEGIN> and <END> markers though, and especially <no new messages> one. You should make them optional, perhaps add verbose arg to dsp_logbuf_print(). Unix way of things is to stay silent when things are going well.

Also code like


syscalls.printf("hello ");
syscalls.printf("world\n");

is producing 2 lines of output. This makes it harder to do things like printing out arrays on one line - it would require printing to temporary buffer instead of just for (...) printf("%d ", i); like with normal printf.

It might make sense to have

#define printf syscalls.printf

or at least do something so that accidentally using just printf() results in a clear error, as right now it just causes linker to print strange warning and then runtime segfault when you try to use such .out file.

Having printf I've found one issue already, it seems you are not clearing .bss section? I have code like:


static int counter; // goes to .bss
// ...
// in exec():
  syscalls.printf("counter %d\n", counter);
  counter++;

This counter retains it's value on GPP program restarts and on recompiled DSP module reloads. I think in both cases it must be cleared (well actually doing it on dsp_open() or dsp_component_load() should be enough).
 
Last edited by a moderator:
I really hate those <BEGIN> and <END> markers though, and especially <no new messages> one. You should make them optional, perhaps add verbose arg to dsp_logbuf_print(). Unix way of things is to stay silent when things are going well.
I anticipated that. It helped to debug the implementation but it should be optional, I agree ( (LOG_DEBUG_LEVEL > 0) or sth)

Also code like


syscalls.printf("hello ");
syscalls.printf("world\n"); is producing 2 lines of output.
ok, I'll change it so that an implicit newline is only printed after the last message (if it did not end with a LF)

It might make sense to have

#define printf syscalls.printf

or at least do something so that accidentally using just printf() results in a clear error, as right now it just causes linker to print strange warning and then runtime segfault when you try to use such .out file.
good idea, consider it done.

Having printf I've found one issue already, it seems you are not clearing .bss section?
take a look at test_logbuf.c, I added a comment about that (found the same issue).

I am not sure why this happens, the component structure initialization works fine for example.

definitely a "(todo)".

(btw, you probably won't believe me when I say that it took 2h to code this, then another 2h to debug the damn suspend/resume thing. for some reason TI thought it was a good idea to not implement #pragma NOINIT or at least type=NOINIT in their COFF linker. geeeez!!)
 
I'm trying to use dsp_shm_alloc() and it's unclear how to check if it failed or not. The doc-comment says "Returns 0 on success" but it can't really do that. Maybe it should actually return int and fill user-supplied dsp_mem_region_t instead?
 
Code:
   /* Allocate contiguous memory block */
   shm = dsp_shm_alloc(DSP_CACHE_RW, TC_SHM_ACCESS_SIZE);
   
   if(0 != shm.size)
   {
 
however the linker appears to crash sadly:
 I presume you are referring to these messages
[..] BFD (Sourcery CodeBench Lite 2011.09-70) 2.21.53.20110905 assertion fail /scratch/jwlemke/2011.09-arm-linux-eabi-lite/obj/binutils-src-2011.09-70-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:11463don't worry, I get them too and have not seen any runtime/crash issues because of them.
Thanks; that is somewhat reassuring (as reassuring as linker asserts can be), I'll continue with getting the other toolchain for the DSP set up tonight and try and get something compiling.
 
   /* Allocate contiguous memory block */
   shm = dsp_shm_alloc(DSP_CACHE_RW, TC_SHM_ACCESS_SIZE);
   
   if(0 != shm.size)
   {
That's quite nonstandard and unintuitive, should be documented at least.. Can it return smaller size than requested?

This function would also be difficult to use from asm because of returned struct (not that it would likely be needed, but we had one person once who coded his program purely in asm).
 
Last edited by a moderator:
That's quite nonstandard and unintuitive, should be documented at least.. Can it return smaller size than requested?
As I said, the documentation still needs to be cleaned up and doxygen'd. Some bits of it (like this one) may be a outdated. There's plenty of example code to look at, when in doubt.

To answer your question: The function never returns less memory than requested.

This function would also be difficult to use from asm because of returned struct (not that it would likely be needed, but we had one person once who coded his program purely in asm).
It takes exactly the same number of assembly instructions to call the function and only one extra instruction (ldr) is needed to evaluate the result ( (shm.size > 0) vs. (0 == ret) ). You are not seriously calling this difficult, are you ?

The reduced number of instructions in the called fxn itself (at least 2 instructions less) makes up for the extra caller instruction, anyway.

Last but not least, who in his right mind does system programming in assembly ? ppl (including me) did that 20 years ago because C compilers were not as efficient as they are today, and for performance critical loops I can still understand but for one-time alloc/free calls.. *shakes head*

Anyways.. time to check out eDMA3. Have you found any video sequencer / hardware accelerator related docs, btw ? the omap3530 TRM (spruf98x) does not seem to cover it..?!
 
Last edited by a moderator:
It takes exactly the same number of assembly instructions to call the function and only one extra instruction (ldr) is needed to evaluate the result ( (shm.size > 0) vs. (0 == ret) ). You are not seriously calling this difficult, are you ?
Yes but you have to know to pass a pointer to the structure in r0 and shift all other arguments, which is non-obvious and rarely used. Having +/- a few instructions is non-issue of course.
Last but not least, who in his right mind does system programming in assembly ? ppl (including me) did that 20 years ago because C compilers were not as efficient as they are today, and for performance critical loops I can still understand but for one-time alloc/free calls.. *shakes head*
We had one such person, maybe he was working on optimize-for-size demo (4K and the likes)? He disappeared without releasing anything though.
Anyways.. time to check out eDMA3. Have you found any video sequencer / hardware accelerator related docs, btw ? the omap3530 TRM (spruf98x) does not seem to cover it..?!
It's undocumented and super secret.. Early versions of TRM didn't even mention ARM9 and separate video blocks, it was all just one "video accelerator" box. Now at least we have some elements and their registers described.
 
Last edited by a moderator:
It takes exactly the same number of assembly instructions to call the function and only one extra instruction (ldr) is needed to evaluate the result ( (shm.size > 0) vs. (0 == ret) ). You are not seriously calling this difficult, are you ?
Yes but you have to know to pass a pointer to the structure in r0 and shift all other arguments, which is non-obvious and rarely used. Having +/- a few instructions is non-issue of course.
hmm earlier this evening I wrote a simple test program and looked at the compiler's assembly output.

here's what it looks like when calling a function "extern test_t test_fxn_a(unsigned int _sz)":

(test_t is just a struct { int a; int b; int c; })


test_a:
.fnstart
@ args = 0, pretend = 0, frame = 16
@ frame_needed = 0, uses_anonymous_args = 0
str lr, [sp, #-4]!
.save {lr}
.pad #20
sub sp, sp, #20
add r0, sp, #4
mov r1, #4096
bl test_fxn_a

and this is with "extern int test_fxn_b(unsigned int _sz, test_t *_ret)":


test_b:
.fnstart
@ args = 0, pretend = 0, frame = 16
@ frame_needed = 0, uses_anonymous_args = 0
str lr, [sp, #-4]!
.save {lr}
.pad #20
sub sp, sp, #20
mov r0, #4096
add r1, sp, #4
bl test_fxn_b

the functions are called like this:


test_t r = test_fxn_a(0x1000u);

and


test_t r;
int r2;
r2 = test_fxn_b(0x1000u, &r);
as you can see, the code is basically the same and in both cases you do have to know how to pass a pointer to the struct.

But agreed, it's not very common. Hopefully no-one wants support for using libc64 in asm code ;)

Last but not least, who in his right mind does system programming in assembly ? ppl (including me) did that 20 years ago because C compilers were not as efficient as they are today, and for performance critical loops I can still understand but for one-time alloc/free calls.. *shakes head*
We had one such person, maybe he was working on optimize-for-size demo (4K and the likes)? He disappeared without releasing anything though.
Of course, I forgot about the 4k intro programmers. Quite insane. And sometimes incompatible with newer OS versions because some assumed default values changed or some default OS .wav files disappeared :D (okokok, most 4ks don't 'cheat' that way ;) )

Anyways.. time to check out eDMA3. Have you found any video sequencer / hardware accelerator related docs, btw ? the omap3530 TRM (spruf98x) does not seem to cover it..?!
It's undocumented and super secret.. Early versions of TRM didn't even mention ARM9 and separate video blocks, it was all just one "video accelerator" box. Now at least we have some elements and their registers described.
Hmm.. maybe we should try to ask TI for the docs ?!.

Usually companies pay royalties for including hardware blocks / IP in their products, and the HW is definitely there.

I don't see any good reason why they would withhold the documentation for it.

The TRM does not really say what exactly this "video accelerator" actually accelerates (just a few lines that say "improved motion estimation", "loop filtering" and "dedicated sequencer" .. you have read them).

In earlier versions of the TRM the whole DSP was only mentioned with the comment "documentation not publically available". Fortunately that has changed later on.

This is an ASM game I believe http://boards.openpa...rc/?hl=assembly
quite crazy. but.. then again.. not so crazy if you haven't done something like that before / do it for practice and to learn how the OS works.



Today I spent quite some time analyzing the reason why the DSP does not see the correct values of global variables in overlay images (except for the component struct but that only worked since it was linked to a dedicated section).


Here are my findings ("doc/overlay_cinit_analysis-22Oct2013.txt"):


----------------------------------------------------------------------------------------------------
test #1:

           in makefile.c64p: OPTFLAGS+= $(OPTFLAGS_SIZE)
in test_logbuf.c:<global>  : int cnt_i = 42;
                in map file: 8620189c   _cnt_i
in test_logbuf.c:loc_init(): syscalls.mlb_debug_usr(3, (sU32)cnt_i);
                     result: [dbg] dsp_debug_usr_print: debug_usr[3]=0x00000000.

  ==> whoops, debug should read 0x2a (42)!!


----------------------------------------------------------------------------------------------------
test #2:

           in makefile.c64p: OPTFLAGS+= $(OPTFLAGS_SIZE)
in test_logbuf.c:<global>  : int cnt_i = 42;
                in map file: 8620189c   _cnt_i
in test_logbuf.c:loc_init(): syscalls.mlb_debug_usr(3, *(volatile sS32*) 0x8620189c); //cnt_i
                     result: [dbg] dsp_debug_usr_print: debug_usr[3]=0x0000002a.

  ==> correct data, cinit works


----------------------------------------------------------------------------------------------------
test #3:

           in makefile.c64p: OPTFLAGS+= $(OPTFLAGS_SIZE)
in test_logbuf.c:<global>  : int cnt_i = 64;
                in map file: 8620189c   _cnt_i
in test_logbuf.c:loc_init(): syscalls.mlb_debug_usr(3, (sU32) &cnt_i);
                     result: [dbg] dsp_debug_usr_print: debug_usr[3]=0x860555c0.

  ==> whoops, DSP uses wrong address of cnt_i although it's listed correctly in the .map file!
 

----------------------------------------------------------------------------------------------------
test #4:

           in makefile.c64p: OPTFLAGS+= $(OPTFLAGS_NONE)
in test_logbuf.c:<global>  : int cnt_i = 64;
                in map file: 86201854   _cnt_i
in test_logbuf.c:loc_init(): syscalls.mlb_debug_usr(3, (sU32) &cnt_i);
                     result: [dbg] dsp_debug_usr_print: debug_usr[3]=0x860555c0.

  ==> still the wrong address


----------------------------------------------------------------------------------------------------
test #5:

           in makefile.c64p: OPTFLAGS+= $(OPTFLAGS_NONE_INTERLIST)
              in install.mk: CFLAGS+= --mem_model:data=far   (note: default is far_aggregate)
in test_logbuf.c:<global>  : int cnt_i = 64;
                in map file: 86201880   _cnt_i
in test_logbuf.c:loc_init(): syscalls.mlb_debug_usr(3, (sU32) &cnt_i);
                     result: [dbg] dsp_debug_usr_print: debug_usr[3]=0x86201880.

  ==> correct address, yay!
I.e. changing the memory model fixes it!

Here's the changelog / update for today:

+ add dsp_cache_wbinvall() API call


+ change GPP-side cache type of overlay region to write-through (instead of noncached)


+ add C64_IOCTL_CACHE action C64_CACHE_AC_WBINVALL to kmod/dev.c


+ analyze DSP-side global var issue (see doc/overlay_cinit_analysis-22Oct2013.txt)


+ change DSP const/data memory model to 'far' (instead of 'far_aggregate')


   --> DSP code now uses correct addresses for global vars.


   --> malloc()/free() also work now but should probably not be used (at least not across RPCs)


+ add redirects for DSP-side puts/printf/vprintf/ calls (trigger linker errors)


   (--> please use syscalls.puts(), syscalls.printf(), .. instead)


+ GPP side dsp_logbuf_print() now omits <begin>, <end>, <no new message> unless debug level is >=20


+ DSP logbuf message lines are now prefixed with "DSP: " on GPP side


+ fix logbuf message lines that are composed via multiple printf()s


+ add TC_LOGBUF_SPLITLINE testcase to tests/c64_tc.c


+ auto-append linefeed in dsp_logbuf_print() to last message if it did not end with LF already


+ add TC_LOGBUF_NO_LF testcase to tests/c64_tc.c


+ fix dsp_shm_alloc(), dsp_fshm_alloc() inline docs (regarding their return values)


+ release http://tkscript.de/c64_tools/c64_tools-22Oct2013_snapshot.tar.gz
 
Last edited by a moderator:
Back
Top