AM6422: Program entry point is incorrect

Part Number: AM6422

I am use CCS v12, MCU SDK+ AM64X v 11_02_00_24.

I am using example project "open-pru\examples\empty_c" as a starting point. When I build and load to me TMDS64VM, it works as expected.

I manually add a new code file to the project to expand on the functionality, and the new code file is added ahead of "main" in the resulting binary file, resulting in the program incorrectly starting execution at the new code file instead of main. [Starts at "PRU_SetupFrameTimer" in map file shown below.] How do I force main back to the program entry point?

 

Memory map resulting from this:

SECTION ALLOCATION MAP

 output                                  attributes/
section   page    origin      length       input sections
--------  ----  ----------  ----------   ----------------
.text      0    00000000    000001f4     
                  00000000    000000dc     PRU_Timer.obj (.text:PRU_SetupFrameTimer)
                  000000dc    00000084     main.obj (.text:main)
                  00000160    00000070     PRU_TaskManager.obj (.text:PRU_SetupTaskMgr)
                  000001d0    00000024     PRU_TaskManager.obj (.text:TestFunction)

.data      1    00000000    0000001d     
                  00000000    00000010     main.obj (.data)
                  00000010    00000008     PRU_Timer.obj (.data:ui64IEP0Cmp0Count)
                  00000018    00000004     PRU_TaskManager.obj (.data)
                  0000001c    00000001     PRU_Timer.obj (.data)

.cinit     1    00000000    00000000     UNINITIALIZED



...



GLOBAL SYMBOLS: SORTED ALPHABETICALLY BY Name 

page  address   name                          
----  -------   ----                          
0     00000000  PRU_SetupFrameTimer           
0     00000160  PRU_SetupTaskMgr              
0     000001d0  TestFunction                  
abs   00033000  __PRU_CREG_BASE_MII_G_RT      
abs   00032400  __PRU_CREG_BASE_MII_MDIO      
abs   00032000  __PRU_CREG_BASE_MII_RT  

...

abs   0000001f  __PRU_CREG_RSVD31             
abs   0000000a  __PRU_CREG_TM_CFG_PRU1        
abs   ffffffff  __c_args__                    
1     00000008  frame                         
1     00000018  framecount                    
0     000000dc  main                          
1     0000000c  sharedRAM                     
1     00000000  step                          
1     00000010  ui64IEP0Cmp0Count             
1     0000001c  ui8IEP0Cmp0Incr               
1     00000004  wait          
  • Hello Seth,

    Did you get this figured out yet?

    In general, I would expect that C does NOT start execution with main, since that would skip initialization of the C infrastructure. That's why I am dropping --entry_point=main from the example.projectspec files which are targeted for C projects, that is an ASM-only setting.

    Note to future readers: these URLs will NOT show the same thing when you read them later in time, since I am pointing Seth to a work-in-progress.

    current CCS settings which I believe are wrong: https://github.com/TexasInstruments/open-pru/blob/main/examples/empty_c/firmware/am64x-evm/icss_g0_pru0_fw/ti-pru-cgt/example.projectspec 

    current draft of the fix: https://github.com/TexasInstruments/open-pru/blob/a0226750_remove_mcuplus_dependencies/examples/empty_c/firmware/am64x-evm/icss_g0_pru0_fw/ti-pru-cgt/example.projectspec 

    Please note that in order to load PRU C code from an MCU+ core using the PRUICSS API, the firmware needs to be compiled with linker flag --ram_model so that the R5F core can initialize the DMEM region separately. I have not had time to add that to the example.projectspec file above yet, but you can find some more information here: https://github.com/TexasInstruments/open-pru/commit/5d72f4e9084f138ff6b1dcd418733a1163fa620b 

    Regards,

    Nick

  • I did resolve this after some trial and error. I forget the exact order, but I ended up stealing a copy of a "boot.c" routine from the SDK and trimming it down to just the routine I needed (_c_int00_noinit_noargs), defining the entry_point flag in the linker to that routine, and then using the linker file SECTIONS definition to place that routine at PRU memory offset 0. That both resolved my proper entry call tree, and also fixed an issue I was having with my stack pointer __SP not being properly initialized. Which raises another couple of questions...

    1) I'm glad you mentioned the "ram_model" compiler option, because I will need that long term. Is there any more detail on what --ram_model does, or what I need to do in my PRU or R5F C code to ensure that data is properly initialized?

    2) I stumbled across __SP being initialized in the SDK boot.c file, but was not able to find that keyword elsewhere in documentation. I assume there may be other built in registers I need to initialize as well (for instance .bss,.data, etc sections of the PRU) from the Arm core when loading. What document contains this information? "PRU Optimizing C/C++ Compilter v2.3 User's Guide" section 4.3.5 lists out the various initialized and uninitalized regions, but its not clear how these sections are initialized in code.

    Thank you!

  • Hello Seth,

    Glad to hear you were able to keep making progress.

    Future readers, the updates that I was talking about with Seth are in this pull request. I will tag these updates as OpenPRU v2026.1.0 next week:
    https://github.com/TexasInstruments/open-pru/pull/125

    The official documentation on --ram_model vs --rom_model is all in the PRU C compiler User's guide / PRU Assembly Language tools. For some reason google search isn't showing the latest version of the assembly document for me, so here are the links which will always take you to the latest version:
    https://www.ti.com/lit/spruhv7
    https://www.ti.com/lit/spruhv6 

    --ram_model vs --rom_model comes down to how the DMEM gets initialized (there may be other differences, but that's the part that I have had to work around this year). For --ram_model, if anything in the DMEM needs to get initialized, the PRU core relies on whoever initialized the PRU subsystem to load that data. For --rom_model, the values going into DMEM are initially stored in instruction memory (IMEM). So the entity initializing the PRU subsystem loads IMEM, and then the PRU core handles copying data from IMEM into DMEM.

    The --rom_model option limits your code size if you have a lot of instructions to execute, since the DMEM values are taking up space in IMEM. However, the data is also compressed a bit differently. In the few tests I ran, total file size for the PRU binaries was about the same or slightly smaller with --ram_model, but I have been told that if a lot of data is getting loaded into DMEM (for example, if you have a look up table, or LUT), then the compression may mean that the total size of the PRU binary will be smaller. That probably isn't a careabout for you if you're using a processor as big as the AM64x.

    I bet __SP is stack pointer, I can't remember which PRU register is used for that by default. Check the documents above, it's probably listed there.

    Regards,

    Nick