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/PROCESSOR-SDK-AM335X: Forward referenced labels not available in assembler symbol table during macro invocation

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

Tool/software: TI C/C++ Compiler

clpru version: ti-cgt-pru_2.1.4

During development of a pseudo-op macro, one often finds it necessary to use the Substitution Symbol Functions such as $isdefed(arg) used to differentiate between a constant and an assembly label symbol. The code below shows the pseudo-op MOV macro instruction used before and after the label "MY_LABEL".

    MOV        r31, MY_LABEL
MY_LABEL:
    MOV        r31, MY_LABEL

Use of the function $isdefed("MY_LABEL") in the MOV pseudo-op before "MY_LABEL" results in $isdefed("MY_LABEL") == 0, while in the MOV pseudo-op after "MY_LABEL" results in $isdefed("MY_LABEL") == 1. This appears to suggest that macro expansion takes place within a single pass parser. A robust assembler might want to parse label symbols in a first pass to obtain a complete symbol table prior to op-code evaluation.

Also I have noticed that $isreg(arg) is non-functional.

  • So that I understand all the details, please supply a test case which demonstrates this problem.  It has to be something that I can build.  Be sure to show all the build options exactly as the compiler shell (clpru) sees them.

    Thanks and regards,

    -George

  • George,

             Please find below the macro definitions that were used in identifying the abnormalities.

    The assembly test code 'mov_macro_trest.asm' used can also be found subsequently.

    The clpru command line invocation used is:

    root@debian-8:/home/brendan/ti-cgt-pru_2.1.4/example#

    ../bin/clpru $build_root/ti-cgt-pru_2.1.4/example/mov_macro_test.asm \

    $build_root/ti-cgt-pru_2.1.4/example/test_xeno_pruss.c \

    --run_linker --ram_model --output_all_sims \

    -i $build_root/ti-cgt-pru_2.1.4/lib \

    --output_file=$build_root/ti-cgt-pru_2.1.4/example/mov_macro_test.bin \

    --library=AM3359_PRU.cmd

    ;*********
    ;* Macros
    ;*********

    ISREG .macro arg, result
        .asg "r31,r30,r29,r28,r27,r26,r25,r24,r23,r22,r21,r20,r19,r18,r17,r16,r15,r14,r13,r12,r11,r10,r9,r8,r7,r6,r5,r4,r3,r2,r1,r0,R31,R30,R29,R28,R27,R26,R25,R24,R23,R22,R21,R20,R19,R18,R17,R16,R15,R14,R13,R12,R11,R10,R9,R8,R7,R6,R5,R4,R3,R2,R1,R0", int_regs
        .asg "r31.b0,r31.b1,r31.b2,r31.b3,R31.b0,R31.b1,R31.b2,R31.b3,r30.b0,r30.b1,r30.b2,r30.b3,R30.b0,R30.b1,R30.b2,R30.b3,r29.b0,r29.b1,r29.b2,r29.b3,R29.b0,R29.b1,R29.b2,R29.b3,r28.b0,r28.b1,r28.b2,r28.b3,R28.b0,R28.b1,R28.b2,R28.b3,r27.b0,r27.b1,r27.b2,r27.b3,R27.b0,R27.b1,R27.b2,R27.b3,r26.b0,r26.b1,r26.b2,r26.b3,R26.b0,R26.b1,R26.b2,R26.b3,r25.b0,r25.b1,r25.b2,r25.b3,R25.b0,R25.b1,R25.b2,R25.b3,r24.b0,r24.b1,r24.b2,r24.b3,R24.b0,R24.b1,R24.b2,R24.b3,r23.b0,r23.b1,r23.b2,r23.b3,R23.b0,R23.b1,R23.b2,R23.b3,r22.b0,r22.b1,r22.b2,r22.b3,R22.b0,R22.b1,R22.b2,R22.b3,r21.b0,r21.b1,r21.b2,r21.b3,R21.b0,R21.b1,R21.b2,R21.b3,r20.b0,r20.b1,r20.b2,r20.b3,R20.b0,R20.b1,R20.b2,R20.b3,r19.b0,r19.b1,r19.b2,r19.b3,R19.b0,R19.b1,R19.b2,R19.b3,r18.b0,r18.b1,r18.b2,r18.b3,R18.b0,R18.b1,R18.b2,R18.b3,r17.b0,r17.b1,r17.b2,r17.b3,R17.b0,R17.b1,R17.b2,R17.b3,r16.b0,r16.b1,r16.b2,r16.b3,R16.b0,R16.b1,R16.b2,R16.b3,r15.b0,r15.b1,r15.b2,r15.b3,R15.b0,R15.b1,R15.b2,R15.b3,r14.b0,r14.b1,r14.b2,r14.b3,R14.b0,R14.b1,R14.b2,R14.b3,r13.b0,r13.b1,r13.b2,r13.b3,R13.b0,R13.b1,R13.b2,R13.b3,r12.b0,r12.b1,r12.b2,r12.b3,R12.b0,R12.b1,R12.b2,R12.b3,r11.b0,r11.b1,r11.b2,r11.b3,R11.b0,R11.b1,R11.b2,R11.b3,r10.b0,r10.b1,r10.b2,r10.b3,R10.b0,R10.b1,R10.b2,R10.b3,r9.b0,r9.b1,r9.b2,r9.b3,R9.b0,R9.b1,R9.b2,R9.b3,r8.b0,r8.b1,r8.b2,r8.b3,R8.b0,R8.b1,R8.b2,R8.b3,r7.b0,r7.b1,r7.b2,r7.b3,R7.b0,R7.b1,R7.b2,R7.b3,r6.b0,r6.b1,r6.b2,r6.b3,R6.b0,R6.b1,R6.b2,R6.b3,r5.b0,r5.b1,r5.b2,r5.b3,R5.b0,R5.b1,R5.b2,R5.b3,r4.b0,r4.b1,r4.b2,r4.b3,R4.b0,R4.b1,R4.b2,R4.b3,r3.b0,r3.b1,r3.b2,r3.b3,R3.b0,R3.b1,R3.b2,R3.b3,r2.b0,r2.b1,r2.b2,r2.b3,R2.b0,R2.b1,R2.b2,R2.b3,r1.b0,r1.b1,r1.b2,r1.b3,R1.b0,R1.b1,R1.b2,R1.b3,r0.b0,r0.b1,r0.b2,r0.b3,R0.b0,R0.b1,R0.b2,R0.b3", byte_regs
        .asg "r31.w0,r31.w1,r31.w2,R31.w0,R31.w1,R31.w2,r30.w0,r30.w1,r30.w2,R30.w0,R30.w1,R30.w2,r29.w0,r29.w1,r29.w2,R29.w0,R29.w1,R29.w2,r28.w0,r28.w1,r28.w2,R28.w0,R28.w1,R28.w2,r27.w0,r27.w1,r27.w2,R27.w0,R27.w1,R27.w2,r26.w0,r26.w1,r26.w2,R26.w0,R26.w1,R26.w2,r25.w0,r25.w1,r25.w2,R25.w0,R25.w1,R25.w2,r24.w0,r24.w1,r24.w2,R24.w0,R24.w1,R24.w2,r23.w0,r23.w1,r23.w2,R23.w0,R23.w1,R23.w2,r22.w0,r22.w1,r22.w2,R22.w0,R22.w1,R22.w2,r21.w0,r21.w1,r21.w2,R21.w0,R21.w1,R21.w2,r20.w0,r20.w1,r20.w2,R20.w0,R20.w1,R20.w2,r19.w0,r19.w1,r19.w2,R19.w0,R19.w1,R19.w2,r18.w0,r18.w1,r18.w2,R18.w0,R18.w1,R18.w2,r17.w0,r17.w1,r17.w2,R17.w0,R17.w1,R17.w2,r16.w0,r16.w1,r16.w2,R16.w0,R16.w1,R16.w2,r15.w0,r15.w1,r15.w2,R15.w0,R15.w1,R15.w2,r14.w0,r14.w1,r14.w2,R14.w0,R14.w1,R14.w2,r13.w0,r13.w1,r13.w2,R13.w0,R13.w1,R13.w2,r12.w0,r12.w1,r12.w2,R12.w0,R12.w1,R12.w2,r11.w0,r11.w1,r11.w2,R11.w0,R11.w1,R11.w2,r10.w0,r10.w1,r10.w2,R10.w0,R10.w1,R10.w2,r9.w0,r9.w1,r9.w2,R9.w0,R9.w1,R9.w2,r8.w0,r8.w1,r8.w2,R8.w0,R8.w1,R8.w2,r7.w0,r7.w1,r7.w2,R7.w0,R7.w1,R7.w2,r6.w0,r6.w1,r6.w2,R6.w0,R6.w1,R6.w2,r5.w0,r5.w1,r5.w2,R5.w0,R5.w1,R5.w2,r4.w0,r4.w1,r4.w2,R4.w0,R4.w1,R4.w2,r3.w0,r3.w1,r3.w2,R3.w0,R3.w1,R3.w2,r2.w0,r2.w1,r2.w2,R2.w0,R2.w1,R2.w2,r1.w0,r1.w1,r1.w2,R1.w0,R1.w1,R1.w2,r0.w0,r0.w1,r0.w2,R0.w0,R0.w1,R0.w2", word_regs

        .asg "", reg

        .loop 64
            .if ($ismember(reg, int_regs))                            ; get the next reg definition string from list
                .if ($symcmp(arg, reg) == 0)
                    .mmsg "Argument string is valid INT register"
                    .eval 1, result
                    .break
                .endif
            .endif
        .endloop

        .loop 256
            .if ($ismember(reg, byte_regs))                            ; get the next reg definition string from list
                .if ($symcmp(arg, reg) == 0)
                    .mmsg "Argument string is valid BYTE register"
                    .eval 1, result
                    .break
                .endif
            .endif
        .endloop

        .loop 192
            .if ($ismember(reg, word_regs))                            ; get the next reg definition string from list
                .if ($symcmp(arg, reg) == 0)
                    .mmsg "Argument string is valid WORD register"
                    .eval 1, result
                    .break
                .endif
            .endif
        .endloop

        .if !($symcmp(result, "1") == 0)                            ; report error
            .mmsg "ISREG: Argument not valid register"    
        .endif
        
        .endm

    ;******************************************************************
    ; Move Register
    ; Description:    Loads upto a 32-bit constant, 13-bit label value
    ;                or register from 'src' to a valid 'dst' register.
    ;******************************************************************
    MOV .macro dst,src
        .asg "b", b
        .asg "w", w
        .asg 0, is_src_reg
        .asg 0, is_dst_reg

        ISREG    src, is_src_reg
        ISREG    dst, is_dst_reg
        .if ($symcmp(is_dst_reg, "1") == 0)
            .mmsg "Destination argument is valid symbol name"
            .if $firstch(dst,b)                                    ; if dst is BYTE reg
                .mmsg "Destination reg is BYTE"
                .if ($symcmp(is_src_reg, "1") == 0)                ; if src is a REG
                    .mmsg "Source is a register"    
                    AND        dst, src, src
                .elseif $isdefed(src)                            ; if src is a defined SYMBOL label in 8k instruction addr space
                    .mmsg "Source is a symbol"
                    LDI        dst, src
                .elseif $isname(src)                            ; if src is possible forward referenced SYMBOL label
                    .mmsg "***Source is forward referenced symbol name"    
                    LDI        dst, src
                .elseif $iscons(src)                            ; if src is a CONST
                    .mmsg "Source is a constant"
                    LDI        dst, src & 0xFF
                .else
                    .mmsg "***Assuming constant source argument"
                    LDI        dst, src & 0xFF
                .endif
            .elseif $firstch(dst,w)                                ; if dst is WORD reg
                .mmsg "Destination reg is WORD"
                .if ($symcmp(is_src_reg, "1") == 0)                ; if src is a REG
                    .mmsg "Source is a register"    
                    AND        dst, src, src
                .elseif $isdefed(src)                            ; if src is a defined SYMBOL label in 8k instruction addr space
                    .mmsg "Source is a symbol"
                    LDI        dst, src
                .elseif $isname(src)                            ; if src is possible forward referenced SYMBOL label
                    .mmsg "***Source is forward referenced symbol name"    
                    LDI        dst, src
                .elseif $iscons(src)                            ; if src is a CONST
                    .mmsg "Source is a constant"
                    LDI        dst, src & 0xFFFF
                .else
                    .mmsg "***Assuming constant source argument"
                    LDI        dst, src & 0xFFFF
                .endif
            .else                                                ; else dst is INT reg    
                .mmsg "Destination reg is INT"
                .if ($symcmp(is_src_reg, "1") == 0)                ; if src is a REG
                    .mmsg "Source is a register"    
                    AND        dst, src, src
                .elseif $isdefed(src)                            ; if src is a defined SYMBOL lable in 8k instruction addr space
                    .mmsg "Source is a symbol"    
                    LDI        dst, src
                .elseif $isname(src)                            ; if src is possible forward referenced SYMBOL label
                    .mmsg "***Source is forward referenced symbol name"    
                    LDI        dst, src
                .elseif $iscons(src)                            ; if src is a CONST
                    .mmsg "Source is a constant"
                    LDI        dst.w0, src & 0xFFFF
                    LDI        dst.w2, src >> 16
                .else
                    .mmsg "***Assuming constant source argument"
                    LDI        dst.w0, src & 0xFFFF
                    LDI        dst.w2, src >> 16
                .endif
            .endif
        .else
            .emsg "Destination argument not valid predefined register"
        .endif
        .endm

    ;*************************************************************

    ; mov_macro_test.asm

    ;*************************************************************
    ;
    ; Include the defines and macros header file
        .include "PRU_hardI2C_IET_Interrupt_h.asm"

        .define "0x100", SHARED_RAM
        .define 0x100000, DDR_RAM

    LABEL:
        .mmsg "mov_macro_test_v1.0"
    ;    MOV        r0, R5            ; MOV R5, 32-bit reg
    ;    MOV        r0, r1            ; MOV r0, 32-bit reg
    ;    MOV        r0, r1.b0        ; MOV r0, r1.b0
    ;    MOV        r0, r1.w2        ; MOV r0, r1.w2
    ;    MOV        r0.b0, r1        ; MOV r0,b0, r1
    ;    MOV        r0.w1, r1        ; MOV r0.w1, r1

        MOV        R0.b3, SHARED_RAM
        MOV        R0.w2, SHARED_RAM
        MOV        R0, SHARED_RA
        MOV        R0.b3, LABEL
        MOV        R0.w2, LABEL
        MOV        R0, LABEL

        MOV        r31, LABEL
        MOV        R32, LABEL        ; ****** ERROR ******

        MOV     r1, PRU1_CTRL+CTPPR0

        MOV        r31, ISR_JUMP64_TABLE
    ISR_JUMP64_TABLE:
        MOV        r31, ISR_JUMP64_TABLE

        MOV        r31, NOT_VALID_LABEL

        MOV        R31, R2
        MOV        R31.b3, R2
        MOV        R31.w1, R2
        MOV        R31.b0, R2.w2

    ;    MOV        r0.w0, 0x100
    ;    MOV32    r0, SHARED_RAM
    ;    MOV     r0, SHARED_RAM    ; MOV r0, CONSTANT
    ;    MOV        r0, LABEL        ; MOV r0, SYMBOL

  • I do not see any unexpected errors with this test case.  This line ...

    Brendan Graham said:
        MOV        R32, LABEL        ; ****** ERROR ******

    ... gets these diagnostics.  

     ***** USER MESSAGE ***** - ISREG: Argument not valid register
      ***** USER MESSAGE ***** - ISREG: Argument not valid register
     "file.asm", ERROR!   at line 156: [ ***** USER ERROR ***** - ] Destination argument not valid predefined register

    But that is expected.  Neither R32 nor LABEL are valid registers. And the destination argument (R32) is not a valid register.  R31 is the last valid register.

    There are errors on later instructions.  But they all refer to symbols like CTPPR0 which are probably defined in this file ...

    Brendan Graham said:
        .include "PRU_hardI2C_IET_Interrupt_h.asm"

    I had to comment that line out, because I don't have that file.

    Your original complaint centered on invoking a macro with an argument that is a label defined later in the file.  I see no instances of that in this test case.

    Thanks and regards,

    -George

  • George,

             Thank you for your response.

    The test pseudo-op instruction MOV        R32, LABEL  was inserted intentionally to produce an error. Naturally I am well aware that R32 is NOT an instruction. This is the whole point of the particular test case. The comment ; ****** ERROR ****** has also been placed there intentionally so as to alert the user that an error is to be expected. This is however, not part of my problem statement.

    The ONLY test case that is relevant to this discussion is the following pseudo-op with forward referenced label argument:

        MOV        r31, ISR_JUMP64_TABLE
    ISR_JUMP64_TABLE:

    Notice that the label is a valid SYMBOL name so that, referring to the MOV macro pseudo-op test code snippet below, the .elseif $isname(src)  test will be selected. Thus the message "***Source is forward referenced symbol name" will be output to stdio. I claim that this action appears erroneous, as the previous test .elseif $isdefed(src) should have returned a '1' as the forward referenced label ISR_JUMP64_TABLE should indeed have been appended to the symbol table, if of course a dual pass AST parser was uses to parse label symbols in the first pass.

            .else                                                ; else dst is INT reg    
                .mmsg "Destination reg is INT"
                .if ($symcmp(is_src_reg, "1") == 0)                ; if src is a REG
                    .mmsg "Source is a register"    
                    AND        dst, src, src
                .elseif $isdefed(src)                            ; if src is a defined SYMBOL lable in 8k instruction addr space
                    .mmsg "Source is a symbol"    
                    LDI        dst, src
                .elseif $isname(src)                            ; if src is possible forward referenced SYMBOL label
                    .mmsg "***Source is forward referenced symbol name"    
                    LDI        dst, src

    Also notice that the following test case using the identical pseudo-op, argument and label produces the message "Source is a symbol" indicative that the branch .elseif $isdefed(src) was taken and furthermore that the parser had previously appended the label ISR_JUMP64_TABLE to the symbol table. This appears to suggest that the parser is a single pass parser and expands macros on the fly and thus produces erroneous results with forward referenced labels as arguments as such labels ahve not yet been appended to the symbol table. Anyway I think that any good assembler should create the symbol table before expanding macros.

    ISR_JUMP64_TABLE:
        MOV        r31, ISR_JUMP64_TABLE

  • To understand how the built-in substitution symbol function $isdefed works, please consider this example.

    	.data
    
    sym1:   .byte	10	; define sym1
    
    ; test the built-in functions
    	.byte	$isdefed("sym1")
    	.byte	$isdefed("sym2")
    
    sym2:	.byte	20	; define sym2
    	
    ; test the built-in functions
    	.byte	$isdefed("sym1")
    	.byte	$isdefed("sym2")

    Assemble that with the command: clpru -al file.asm .  That creates a listing file with the extension .lst.  Here are the key lines from that listing file.

           3 00000000 0000000000000A  sym1:   .byte   10      ; define sym1
           4
           5; test the built-in functions
           6 00000001 00000000000001          .byte   $isdefed("sym1")
           7 00000002 00000000000000          .byte   $isdefed("sym2")
           8
           9 00000003 00000000000014  sym2:   .byte   20      ; define sym2
          10
          11; test the built-in functions
          12 00000004 00000000000001          .byte   $isdefed("sym1")
          13 00000005 00000000000001          .byte   $isdefed("sym2")

    The third column is the interesting one.  It shows the encoding for that line of assembly.  For the lines with $isdefed, it shows the value for that use of $isdefed.  You can see that $isdefed is positional.  The value changes based on whether the symbol, at that point in the assembly file, has a value assigned to it or not.

    I realize this not what you expect.  But $isdefed has worked this way from the beginning.  And not just for the PRU assembler, but for all TI assemblers.

    Thanks and regards,

    -George

  • It has been verified subsequently, that the above discussion developed as a result of erroneously transcribed PRU code assembled with 'clpru', and originally written and assembled under PASM. The JMP/JAL @register instructions take a 32-bit word aligned argument and not a byte sized argument. A '>>2' instruction was apparently accidentally deleted in the code. Incorrectly computed addresses into a jump table led to an entire week of verification activities before the inappropriately transcribed computation error was eventually discovered.