This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/AM3358: Erroneous ti-cgt-pru_2.1.4 (and 2.1.2): error in JMP and JAL to forward referenced label or register argument

Part Number: AM3358
Other Parts Discussed in Thread: PROCESSOR-SDK-AM335X, AM3359

Tool/software: TI C/C++ Compiler

To whom it may concern. I appear to have verified that, for ti-cgt-pru_2.1.4 and ti-cgt-pru_2.1.2, the JMP instruction is non functional WHEN the argument is a 'forward referenced label' or a "register'. The instruction operates correctly on a backward referenced label argument. The QBA instruction however does work correctly with a forward referenced label argument, so that's a solution for label arguments but QBA does not take register arguments. For register arguments one can use the JAL instruction (CALL) in place of JMP as a work around. But alas the JAL instruction is broken as well! Yikes!

Also is not coincidental that my complaint is in regards to forward referenced symbols, once again. My previous post titled "Compiler/PROCESSOR-SDK-AM335X: Forward referenced labels not available in assembler symbol table during macro invocation" also described what I considered a problem with the AST parser not appending the symbol table appropriately in the first pass. Perhaps this may narrow down the search for the source of the assembler bug.

  • You say JMP is "non functional" and that JAL is "broken." I'm not sure what you mean exactly. What incorrect behavior do you see when the problem occurs? Does the assembler reject the statement? Does the assembler translate it incorrectly? Does the instruction not execute properly at run time?
  • The listing file appears in order.

    The JMP instruction does not jump to:
    1. forward referenced label arguments (I have no idea YET if the assembler even actually executes the instruction. I will test this shortly.)
    2. register arguments

    The JAL instruction does not jump to:
    1. forward referenced label arguments (I have no idea YET if the assembler even actually executes the instruction. I will test this shortly.)
    2. register arguments

    I am sure I have not tested every single corner case.
  • Something is being executed for either instruction as instructions immediately subsequent do not execute. A jump appear to be executed but to where I have no idea.
  • JMP to backward referenced label works:

    CORE_LOOP:
    QBBS EVENT_HANDLER, r31, 30
    JMP CORE_LOOP
    EVENT_HANDLER:

    JAL to register contents does not work:
    (verified branch instruction executes but don't know where jumps to)

    LDI r9, ISR_JMP64_TABLE
    ADD r9, r9, 7
    JAL r3.r2, r9.w0
    ... something or the other does not execute here
    ISR_JMP64_TABLE:

    JMP to register contents does not work:
    (verified branch instruction executes but don't know where jumps to)

    LDI r9, ISR_JMP64_TABLE
    ADD r9, r9, 7
    JMP r9.w0
    ... something or the other does not execute here
    ISR_JMP64_TABLE:

    JMP to forward referenced label does not work:
    (verified branch instruction executes but don't know where jumps to)

    JMP ISR_JMP64_TABLE
    ... something or the other does not execute here
    ISR_JMP64_TABLE:
  • Are you able to trace the execution of the JMP/JAL in single-step mode in CCS?
  • I am not using CCS. Running on the Linux command line within a Debian VM on a Windows host ;-) ha ha ha
    Also, setting up a single step debug toolchain is not exactly within the scope of this project.
  • Am I the only person using this compiler/assembler? As you can imaging, without a JMP &register instruction the tool is unusable for all but the most rudimentary inline code.
  • Could this problem have anything at all to do with an improper linker command file? Just a thought. I am using the supplied AM3359_PRU.cmd file.

  • We use the compiler/assembler internally to build and validate. The RTS files have roughly 2000 "JMP reg" instructions and roughly 3000 "JMP imm" instructions, and we are in fact able to run the code, so it comes as a bit of a surprise that something would be wrong with these instructions. I don't know PRU well enough to be able to determine what the problem is, let alone whether the linker command file is involved. I'm trying to gather enough of a test case to enter for analysis.
  • Could you please show me a disassembly sample for one of the JMP/JAL instructions that behave incorrectly? I specifically need to see the opcode.
  • In addition, please describe exactly how you know the jump instructions operate incorrectly.  What are you looking at?  Precisely how do you go about it?

    Thanks and regards,

    -George

  • I have spent the entire day observing the operation of variations of the two instructions JMP and JAL. Find below a snippet of the .lst file demonstration the encoding of several variations of these instructions. Some of the initial inline assembler code is sufficiently functional so that I can write data to PRU SHARED RAM and access this data from the ARM and then visually to a stdio test suite. I am well able to verify code execution at a branch address. No versions of the JMP and JAL instructions execute correctly. I can branch successfully with QBA to the same labels as used with the JMP/JAL tests. The original assembly code executes correctly when assembled with PASM.

         292
         293                                ;*********************************************
         294                                ; CALL .macro dst
         295                                ;       JAL     callReg.w2, dst
         296                                ;       .endm
         297                                ;
         298                                ; Where 'callReg' is defined as 'r3.w2', i.e.
         299                                ;
         300                                ; #define callReg       r3
         301                                ;       %}
         302                                ;*********************************************
         303
         304        ;QBA            IET_CMR0_ISR + 8
         305                                ;--
         306 000001b8 0000002100BC00          JMP             0x2f0
         307                                ;--
         308 000001bc 00000021000000!         JMP             IET_CMR0_ISR
         309                                ;-- above IET_CMR0_ISR = 0x2f0
         310 000001c0 00000020E90000          JMP             regVal
    #                                          JMP             r9
         311                                ;-- above regVal = 0x20c
         312 000001c4                         CALL    IET_CMR0_ISR
    1        000001c4 000000230000C3!         JAL             callReg.w2, dst
    #                                          JAL             r3.w2, IET_CMR0_ISR
    PRU Assembler Unix v2.1.4 Sat Jan 21 21:36:25 2017

    Tools Copyright (c) 2012-2015 Texas Instruments Incorporated
    /home/brendan/ti-cgt-pru_2.1.4/example/PRU_hardI2C_IET_Interrupt.asm PAGE   13

         313                                ;-- above IET_CMR0_ISR = 0x2f0
         314 000001c8                         CALL    0x2f0
    1        000001c8 0000002300BCC3          JAL             callReg.w2, dst
    #                                          JAL             r3.w2, 0x2f0
         315                                ;--  
         316 000001cc 000000230000C3!         JAL             r3.w2, IET_CMR0_ISR
         317                                ;-- above IET_CMR0_ISR = 0x2f0
         318 000001d0 0000002300BCC3          JAL             r3.w2, 0x2f0
         319                                ;---------------------------------------------

    .

    .

    .

         329 000001f0                 ISR_JMP64_TABLE:
         330 000001f0 00000021000000!         JMP             CORE_LOOP
         331 000001f4 00000021000000!         JMP             CORE_LOOP
         332 000001f8 00000021000000!         JMP             CORE_LOOP
         333 000001fc 00000021000000!         JMP             CORE_LOOP
         334 00000200 00000021000000!         JMP             CORE_LOOP
         335 00000204 00000021000000!         JMP             CORE_LOOP
         336 00000208 00000021000000!         JMP             CORE_LOOP
         337 0000020c 00000021000000!         JMP             IET_CMR0_ISR    ; ISR
         338 00000210 00000021000000!         JMP             CORE_LOOP
         339 00000214 00000021000000!         JMP             CORE_LOOP

  • Extensive verification activities suggest that an offset of 0x40 (64-bytes) is subtracted from a label argument for the JAL instruction.

    For example the instruction:

    JAL    r3.w2, MY_LABEL

    actually behaves as:

    JAL    r3.w2, MY_LABEL - 0x40

  • What you're showing us is the listing file output by the assembler for the relocatable object file, not the executable file.  According to the PRU Assembly Language Tools User's Guide, the ! relocation indicator character at the end of the opcode stands for an undefined external reference, which means that some of those zero fields are going to be filled in at link time.  See the PRU Assembly Language Tools User's Guide at

    http://processors.wiki.ti.com/index.php/TI_Compiler_Information#Compiler_Manuals

    So, for instance, the table labeled ISR_JMP64_TABLE has a bunch of instructions with the very same opcode, which is just the opcode for JMP imm, without the actual destination value. As for the instruction at line 306 of the listing, the destination was known at assembly time, so it is present in the opcode, and there is no relocation character.

    The listing file alone is not enough to get insight into this issue. We would also need the dump of the relocation table from the object file that ofdpru gives you. However, it would be better to look at the disassembly of the executable file. If you want to be really sure, send us either:

    1. The linker map file (linker option --map_file)
    2. The executable file (typically named something.out)

    or

    1. The linker map file (linker option --map_file)
    2. The full output of ofdpru -v something.out
    3. The full output of dispru simething.out

    The JMP instruction is not supposed to subtract anything during execution.  There is a 16-bit field in the JMP imm instruction, and that value is multiplied by 4 to get the actual absolute address.

  • The ! symbol: I gathered that it represented a link time operation.

    The argument 0x2f0 at line 306 was not a label, the value of which was inserted by the assembler, but hard coded by me to remove the possibility of label corruption if it existed: one less variable to deal with.

    I will provide your requested files subsequently.

    I am adequately aware that the JAL instruction is not SUPPOSED to subtract anything from the argument during execution. I am merely stating a fact that indeed, for my particular installation of the ti-cgt-pru_2.1.4 tool, the instruction does in fact, in reality, map the argument MY_LABEL -> (MY_LABEL - 0x40 ).

    I am well aware of the 16-bit argument requirement. Actually the 16-bit argument is in fact divided by 4 as represented in the .lst file so as to align with 4-byte instruction size boundaries.
  • Some observations. This is really bizarre.

    For a CALL/RET function, i.e. as follows:

    JAL r3.w2, 0x123 + 0x40 (hard coded)
    ...
    00000123 "some code here"
    ...
    label1: "assembler is fine with this label"
    ...
    label2: "assembler is not fine with this label, and it has been observed that the 'return address+1' originally written in JAL r3.w2, ... appears to be bogus. In some instances if the JMP r3.w2 (RET) instruction is >= 0x40 bytes offset from the called label (address) when the assembler is given the opportunity to replace a label argument (as opposed to hard coded call addr), the return address in r3.w2 is incorrect and the PRU code ends up in lar, lar land.
    ...
    JMP r3.w2

    In the above case, there can exist no more than '1' label within the assembly source between the called address and the JMP r3.w2 (RET) instruction or the return arddress+1 originally inserted into r3.w2, jumps us into lar, lar land.
  • Let me be blunt: I think you're spending a lot of effort going in the wrong direction. I think that if the PRU assembler and linker were getting the encoding wrong as often as you're suggesting, none of our test cases would work. However, our test cases work fine for us. Thus, I doubt the hypothesis. I don't know what's going on with your test cases that causes them to work incorrectly. My best guess right now is that you're trying to execute a relocatable object file, which isn't supported. I suggest that it's not going to be fruitful to send time further characterizing the problem; what will get us there quickly is a test case for which we can reproduce the incorrect behavior.
  • As far as I am concerned, I have never expressly taken any actions to relocate any code. All the code in question works flawlessly when assembled with PASM. Use of the TI clpru assembler is only thing that's different here and the only reason for the attempted transition is so that I can make use of the PRU C/C++ compiler.

    This is my clpru command line:

    # Assembly only build
    ../bin/clpru -ax \
    $build_root/ti-cgt-pru_2.1.4/example/PRU_hardI2C_IET_Interrupt.asm \
    --run_linker --verbose_diagnostics \
    --map_file=PRU_hardI2C_IET_Interrupt.map \
    -i $build_root/ti-cgt-pru_2.1.4/lib \
    --output_file=$build_root/ti-cgt-pru_2.1.4/example/PRU_hardI2C_IET_Interrupt.bin \
    --library=AM335x_PRU.cmd

    This is my linker .cmd file with commented out sections:

    /****************************************************************************/
    /* AM335x_PRU.cmd */
    /* Copyright (c) 2015 Texas Instruments Incorporated */
    /* */
    /* Description: This file is a linker command file that can be used for */
    /* linking PRU programs built with the C compiler and */
    /* the resulting .out file on an AM335x device. */
    /****************************************************************************/

    -cr /* Link using C conventions */
    -stack 0x100
    -heap 0x100


    /* Specify the System Memory Map */
    MEMORY
    {
    PAGE 0:
    PRU_IMEM_0 : org = 0x00000000 len = 0x00002000 /* 8kB PRU0 Instruction RAM */
    PRU_IMEM_1 : org = 0x00002000 len = 0x00002000 /* 8kB PRU1 Instruction RAM */

    PAGE 1:

    /* RAM */

    PRU_DMEM_0 : org = 0x00000000 len = 0x00002000 CREGISTER=24 /* 8kB PRU Data RAM 0 */
    PRU_DMEM_1 : org = 0x00002000 len = 0x00002000 CREGISTER=25 /* 8kB PRU Data RAM 1 */

    PAGE 2:
    PRU_SHAREDMEM : org = 0x00010000 len = 0x00003000 CREGISTER=28 /* 12kB Shared RAM */

    /*
    DDR : org = 0x80000000 len = 0x00000100 CREGISTER=31
    L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30
    */

    /* Peripherals */
    /*
    PRU_CFG : org = 0x00026000 len = 0x00000044 CREGISTER=4
    PRU_ECAP : org = 0x00030000 len = 0x00000060 CREGISTER=3
    PRU_IEP : org = 0x0002E000 len = 0x0000031C CREGISTER=26
    PRU_INTC : org = 0x00020000 len = 0x00001504 CREGISTER=0
    PRU_UART : org = 0x00028000 len = 0x00000038 CREGISTER=7

    DCAN0 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14
    DCAN1 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15
    DMTIMER2 : org = 0x48040000 len = 0x0000005C CREGISTER=1
    PWMSS0 : org = 0x48300000 len = 0x000002C4 CREGISTER=18
    PWMSS1 : org = 0x48302000 len = 0x000002C4 CREGISTER=19
    PWMSS2 : org = 0x48304000 len = 0x000002C4 CREGISTER=20
    GEMAC : org = 0x4A100000 len = 0x0000128C CREGISTER=9
    I2C1 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2
    I2C2 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17
    MBX0 : org = 0x480C8000 len = 0x00000140 CREGISTER=22
    MCASP0_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8
    MCSPI0 : org = 0x48030000 len = 0x000001A4 CREGISTER=6
    MCSPI1 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16
    MMCHS0 : org = 0x48060000 len = 0x00000300 CREGISTER=5
    SPINLOCK : org = 0x480CA000 len = 0x00000880 CREGISTER=23
    TPCC : org = 0x49000000 len = 0x00001098 CREGISTER=29
    UART1 : org = 0x48022000 len = 0x00000088 CREGISTER=11
    UART2 : org = 0x48024000 len = 0x00000088 CREGISTER=12

    RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10
    RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13
    RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21
    RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27
    */
    }

    /* Specify the sections allocation into memory */
    SECTIONS {
    /* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading
    an ELF file, but useful when loading a binary */
    .text:_c_int00* > 0x0, PAGE 0

    .text > PRU_IMEM_0, PAGE 0
    .stack > PRU_DMEM_0, PAGE 1
    .bss > PRU_DMEM_0, PAGE 1
    .cio > PRU_DMEM_0, PAGE 1
    .data > PRU_DMEM_0, PAGE 1
    .switch > PRU_DMEM_0, PAGE 1
    .sysmem > PRU_DMEM_0, PAGE 1
    .cinit > PRU_DMEM_0, PAGE 1
    .rodata > PRU_DMEM_0, PAGE 1
    .rofardata > PRU_DMEM_0, PAGE 1
    .farbss > PRU_DMEM_0, PAGE 1
    .fardata > PRU_DMEM_0, PAGE 1

    .resource_table > PRU_DMEM_0, PAGE 1
    }
  • Brendan Graham said:
    As far as I am concerned, I have never expressly taken any actions to relocate any code. All the code in question works flawlessly when assembled with PASM. Use of the TI clpru assembler is only thing that's different here and the only reason for the attempted transition is so that I can make use of the PRU C/C++ compiler.

    Well, that's one major difference between pasm and clpru: with clpru you must link the code to make an executable file.  Linking does relocation and placement.

    Your clpru command line does include the --run_linker command, so you are linking the program.  You're using the --output_file option, so your executable file is named $build_root/ti-cgt-pru_2.1.4/example/PRU_hardI2C_IET_Interrupt.bin; that's the file we need to examine.

  • As for open sourcing our code base, we have not really considered this a part of the strategy as yet. I have been working on reducing a sample of our code base with an example of the unusual operation but this apparently will take some time as replicating the symptoms appear to depend upon the current label positions. I would like to cooperate with you but there are concerns over open sourcing the entire code base. When I have something scaled down and reproducible I will let you know.
  • Make sure you are loading and executing the executable file, not the relocatable file.
  • I'm specifying the output file to have a .bin extension, and that's what I'm loading. Should I be loading some other file?
  • The name of the linker output file is irrelevant; changing the name doesn't change the output type.  The linker produces an object file; usually it is an absolute, executable object file.  PRU only supports ELF, so the magic number should be (in hex) 7f 45 4c 46, or "^?ELF".

    Please run ofdpru -v on the .bin file and show us the "Object File Information" section.  It should look like this:

     Object File Information
    
        File Name:           a.out                  
        Format:              ELF Version 1          
        File Type:           executable file        
        Machine:             TI PRU                 
        Machine Endian:      little endian          
        Entry Point:         0x00005538             
        Vendor:              Texas Instruments, Inc.
        Producer:            Linker                 
        Linker Version:      2.2.0                  
        Number of Sections:  28                     
        File Length:         246508                 
        ELF Class:           32-bit objects         
        ELF e_flags:         0x00000000             
    
  •     File Name:           PRU_hardI2C_IET_Interrupt.bin
        Format:              ELF Version 1                
        File Type:           executable file              
        Machine:             TI PRU                       
        Machine Endian:      little endian                
        Entry Point:         0x00000000                   
        Vendor:              Texas Instruments, Inc.      
        Producer:            Linker                       
        Linker Version:      2.1.4                        
        Number of Sections:  148                          
        File Length:         20784                        
        ELF Class:           32-bit objects               
        ELF e_flags:         0x00000000         

  • Okay, that is indeed the executable file. It appears my hypothesis was incorrect.
    Well then I really don't know what's going on. It would help to see the object file and map file.
    What program do you use to load the ELF file onto the target?
    Do you do any post-link processing of the executable file?
    Do you relocate the program on the target, perhaps with a boot-loader?
  • I do not post process the binary image.

    Below is how I load the image file to the PRU.
    I am running Linux-Xenomai and let the ARM do the boot loading.

    /************************************************
    * Load and execute the pru binary image to PRU1
    ************************************************/
    rt_printf("\t-> loading PRU1 binary\n");
    prussdrv_exec_program(PRU_NUM1, PRU1_BINARY);
  • ******************************************************************************
    PRU Linker Unix v2.1.4
    ******************************************************************************
    >> Linked Tue Jan 24 12:35:53 2017

    OUTPUT FILE NAME: </home/brendan/ti-cgt-pru_2.1.4/example/PRU_hardI2C_IET_Interrupt.bin>
    ENTRY POINT SYMBOL: "_boot" address: 00000000


    MEMORY CONFIGURATION

    name origin length used unused attr fill
    ---------------------- -------- --------- -------- -------- ---- --------
    PAGE 0:
    PRU_IMEM_0 00000000 00002000 000004d4 00001b2c RWIX

    PAGE 1:
    PRU_DMEM_0 00000000 00002000 00000000 00002000 RWIX
    PRU_DMEM_1 00002000 00002000 00000000 00002000 RWIX

    PAGE 2:
    PRU_SHAREDMEM 00010000 00003000 00000000 00003000 RWIX


    SECTION ALLOCATION MAP

    output attributes/
    section page origin length input sections
    -------- ---- ---------- ---------- ----------------
    .text 0 00000000 000004d4
    00000001 000004d4 PRU_hardI2C_IET_Interrupt.obj (.text)

    .cinit 1 00000000 00000000 UNINITIALIZED


    GLOBAL SYMBOLS: SORTED ALPHABETICALLY BY Name

    page address name
    ---- ------- ----
    0 000001fc ISR_JMP64_TABLE
    abs 00000000 __PRU_CREG_BASE_PRU_DMEM_0
    abs 00002000 __PRU_CREG_BASE_PRU_DMEM_1
    abs 00010000 __PRU_CREG_BASE_PRU_SHAREDMEM
    abs 00000018 __PRU_CREG_PRU_DMEM_0
    abs 00000019 __PRU_CREG_PRU_DMEM_1
    abs 0000001c __PRU_CREG_PRU_SHAREDMEM
    abs ffffffff __binit__
    abs ffffffff __c_args__
    0 00000000 _boot
    abs ffffffff binit


    GLOBAL SYMBOLS: SORTED BY Symbol Address

    page address name
    ---- ------- ----
    0 00000000 _boot
    0 000001fc ISR_JMP64_TABLE
    abs 00000000 __PRU_CREG_BASE_PRU_DMEM_0
    abs 00000018 __PRU_CREG_PRU_DMEM_0
    abs 00000019 __PRU_CREG_PRU_DMEM_1
    abs 0000001c __PRU_CREG_PRU_SHAREDMEM
    abs 00002000 __PRU_CREG_BASE_PRU_DMEM_1
    abs 00010000 __PRU_CREG_BASE_PRU_SHAREDMEM
    abs ffffffff __binit__
    abs ffffffff __c_args__
    abs ffffffff binit

    [11 symbols]
  • Here is what may be a clue. What is the precise meaning and implications of the text "File Offset: 0x00000034" in the excerpt from the .ofd file below?

    <2> ".text"
    Load Address: 0x00000000 Run Address: 0x00000000
    Size: 0x134 Alignment: 4
    Loaded Onto Device: Yes Address Unit Size: 8 bits
    File Offset: 0x00000034 # Relocs: 0
    Section Type: SHT_PROGBITS Page: 0
    ELF sh_flags: 0x00000006 ELF sh_flag: SHF_ALLOC
    ELF sh_flag: SHF_EXECINSTR TI ext_flags: 0x0
  • Brendan Graham said:
    What is the precise meaning and implications of the text "File Offset: 0x00000034"

    That is the byte location, in the executable file, where the contents of the .text section begin.  Note this is not the address of .text in PRU memory.  That is indicated by Run Address, which is 0.

    Thanks and regards,

    -George

  • In the .ofd file, without specifying any .align directive prior to the initial .text section, or equivalently as

    .align 0x0

    .text

    a file offset of 0x34 is observed as in the following excerpt

    <2> ".text"

    Load Address: 0x00000000 Run Address: 0x00000000

    Size: 0x134 Alignment: 64

    Loaded Onto Device: Yes Address Unit Size: 8 bits

    File Offset: 0x00000034 # Relocs: 0

    Section Type: SHT_PROGBITS Page: 0

    ELF sh_flags: 0x00000006 ELF sh_flag: SHF_ALLOC

    ELF sh_flag: SHF_EXECINSTR TI ext_flags: 0x0

    In the same assembly code .text section the following statements were made

    CLREN_INTS:

    00000068 LDI r9.w0, 0x0004 ; account for length of SBCO instruction at address 0xec

    0000006c LDI r9.w2, 0x55aa

    00000070 JAL r3.w2, CLREN_INTR + 0x20 ; the branch instruction under test

    ; @ call address + “test offset” (0x20)

    00000074 SBCO &r9, C28, 4*6, 4 ; instruction @ call address + 0x4

    ; the “return address” (0x00000074)

    . . . some code here

    000000cc ADD r9, r9, 4

    000000d0 ADD r9, r9, 4

    000000d4 ADD r9, r9, 4

    000000d8 ADD r9, r9, 4

    000000dc ADD r9, r9, 4 ; branch instruction at addr 0x70 jumped here instead!!!

    000000e0 ADD r9, r9, 4

    000000e4 ADD r9, r9, 4

    000000e8 ADD r9, r9, 4

    000000ec SBCO &r9, C28, 4*7, 4 ; r9 = 0x55aa0014 written to PRU/ARM shared ram

    ; let's call the byte count in r9.w0 the “residue

    CLREN_INTR:

    000000f0 AND r24, r3, r3

    000000f4 SBCO &r3, C28, 4*8, 4 ; r3 = 0x002a0000 written to PRU/ARM shared ram

    ; r3 = “actual return address” = (call address+0x4)/0x4

    000000f8 AND r9, r24, r24

    000000fc AND r9, r24, r24

    00000100 AND r9, r24, r24

    00000104 AND r9, r24, r24

    00000108 AND r9, r24, r24

    0000010c AND r9, r24, r24

    00000110 AND r9, r24, r24 ; branch instruction at addr 0x70 should have jumped here!!!

    00000114 AND r9, r24, r24

    00000118 AND r9, r24, r24

    0000011c AND r9, r24, r24

    00000120 AND r9, r24, r24

    00000124 AND r9, r24, r24

    00000128 AND r9, r24, r24

    0000012c AND r3, r24, r24

    00000130 JMP r3.w2

    The results of the preceeding apparently erroneous example code can be explained with the following argument. The branch instruction at address 0x70 is expected to branch to address 0x110 but it instead branches to address 0xdc. We know this because the SBCO instruction at address 0xec writes the byte count 0x14 (0x14/4 = 5 instructions), computed beginning at the address of the PC after the branch instruction executes at address 0x70, up until the label CLREN_INTR is written to ARM shared memory and output to stdio The actual return address 0x2a stored in register r3.w2 is written to ARM shared memory and output to stdio. Therefore the following calculation must be true:

    file offset = test offset + residue

    0x34 = 0x20 + 0x14

    If the .text section is explicitly aligned to the offset 0x40 for instance, as

    .align 0x40

    .text

    then the calculation is verified to also be true.

    return address = actual return address + file offset

    0x2d*4 (0xb4) = 0x74 + 0x40

  • The function "prussdrv_pru_write_memory(pru_ram_id, 0, code, codelen)" is always loading the binary executable from offset '0', i.e. the beginning of the file. PASM must be writing a binary with NO offset always. So the question remains as to why clpru does not remove a known offset into the binary file. But this is the job of the linker, to properly resolve symbols based on the offset of entry_symbol from the beginning of the binary file. So here again it appears that the clpru linker is deficient.

    github.com/.../prussdrv.c

    int prussdrv_pru_write_memory(unsigned int pru_ram_id,
    unsigned int wordoffset,
    const unsigned int *memarea,
    unsigned int bytelength)

    {}

    int prussdrv_load_data(int prunum, const unsigned int *code, int codelen)
    {
    unsigned int pru_ram_id;
    if (prunum == 0)
    pru_ram_id = PRUSS0_PRU0_DATARAM;
    else if (prunum == 1)

    pru_ram_id = PRUSS0_PRU1_DATARAM;

    else
    return -1;
    // Make sure PRU sub system is first disabled/reset
    prussdrv_pru_disable(prunum);
    prussdrv_pru_write_memory(pru_ram_id, 0, code, codelen);
    //prussdrv_pru_enable(prunum);
    return 0;

    }

  • Brendan,

    The prussdrv user space library (along with the UIO pruss kernel driver) is meant to load the binary format that is output from the PASM tool.

    The RemoteProc kernel driver is capable of loading the ELF binaries that are output by the TI C compiler/assembler: http://processors.wiki.ti.com/index.php/PRU-ICSS_Remoteproc_and_RPMsg#Remoteproc

    See this e2e answer about how to add a resource_table header (required by RemoteProc) into your assembly file :https://e2e.ti.com/support/arm/sitara_arm/f/791/p/447040/1608294#1608294

     See this hands-on lab for an introduction on how to use the RemoteProc driver to load your firmware into the PRU: http://processors.wiki.ti.com/index.php/PRU_Training:_Hands-on_Labs#LAB_4:_Introduction_to_Linux_driver

    Jason Reeder

    p.s. alternatively there may be a series of steps to convert the ELF binary (from the TI compiler/assembler/linker) into a format that the prussdrv library can use. But any support for prussdrv or PASM will need to come from the BeagleBoard community here: http://beagleboard.org/

  • I am using the Linux-3.8_Xenomai-2.6.4 kernel so Remoteproc an RPMsg was not available as of last May 2016 when I temporarily archived this project. However PRUSSDRV can indeed be used to load a clpru C/C++/assembly binary in the form text.bin, data.bin output from the hexpru tool.

    Generate text.bin and data.bin files with hexpru, as

    ../bin/hexpru bin.cmd compiled_c_cpp_asm_project.out

    In Linux-Xenomai, do

    #define PRU1_BINARY "pasm_binary.bin"

    #define PRU1_DATA_BINARY "data.bin"

    #define PRU1_TEXT_BINARY "text.bin"

    ...

    ...

        /* For use with PASM assembler only .bin files */
        if(prussdrv_exec_program(PRU_NUM1, PRU1_BINARY) == 0) {                /* if found and loaded PASM assembled binary in directory */
              rt_printf("\t-> successfully loaded PRU1 %s \n", PRU1_BINARY);
        } else {                                                            /* else did not find PASM assembled binary */
              rt_printf("\t-> WARNING: failed loading PASM assembled PRU1 %s \n", PRU1_BINARY);    

            /* For use with clpru C/C++/assembler only data.bin files */
            if(prussdrv_load_datafile(PRU_NUM1, PRU1_DATA_BINARY) == 0) {    /* then try to load clpru C/C++/assembler only data.bin files */
                rt_printf("\t-> successfully loaded PRU1 %s \n", PRU1_DATA_BINARY);
            } else {
                  rt_printf("\t-> ERROR: failed loading PRU1 %s \n", PRU1_DATA_BINARY);
                return;
            }

            /* For use with clpru C/C++/assembler only text.bin files */
            if(prussdrv_exec_program(PRU_NUM1, PRU1_TEXT_BINARY) == 0) {    /* then try to load clpru C/C++/assembler only text.bin files */
                rt_printf("\t-> successfully loaded PRU1 %s \n", PRU1_TEXT_BINARY);
            } else {
                  rt_printf("\t-> ERROR: failed loading PRU1 %s \n", PRU1_TEXT_BINARY);
                return;
            }
        }

  • Brendan,

    Does this correct your issue with the JAL offset? Or does the issue persist?

    Jason Reeder

  • Jason,
    The above posted solution provides a simple solution to the problem. Thank you for your assistance.

    Regards,
    Brendan
  • No problem. Thanks for coming back and confirming the fix!

    Jason