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.

Direct Addressing Concerns

I have read all the Texas Instruments (TI) Signal Processing Resource (SPR) documents (and videos) I could find about C28 Direct Addressing.

It has been written that Direct Addressing is supposed to be better and swifter than Indirect Addressing but it appears to be, to me, and most importantly, potentially dangerous.

For Direct Addressing, one should first load the Data Page Pointer (DP) for the variable, which consumes one cycle, to then access the CORRECT variable. If one does not first load DP and assumes that DP is currently correct for a particular variable, it could have disastrous consequences.

For Indirect Addressing, one MUST first load the complete address of the variable, which also consumes one cycle, and there is no need to be concerned if the CORRECT variable is being accessed because it has no association with the current DP value.

Refer to the conversation at: http://e2e.ti.com/support/microcontrollers/c2000/f/171/t/320270.aspx?pi269061=1

 

It also appears to be impossible to reliably (and swiftly) confirm that the DP register is currently loaded CORRECTLY, unless one does reload it each and every time each variable is accessed.

 

Also, because any added, deleted, or changed software variables (or elements of any variable) between compiles could place various variables in completely different Data Pages, one cannot GUARANTEE that the Data Page required for a variable will ALWAYS be the same for other supposedly associated variables (maybe in one compiled version but not in another where variables may have been added, deleted, or resized).

 

Also, one should always set the blocking flag to reset the page boundary when necessary as, for example:

   VarA01: .usect ".ebss", 1, 1 ;blocking flag = 1 to reset page boundary

   VarA02: .usect ".ebss", 1

   VarA03: .usect ".ebss", 1

   VarA60: .usect ".ebss", 1

   VarB01: .usect ".ebss", 1, 1 ;blocking flag = 1 to reset page boundary

   VarB02: .usect ".ebss", 1

   VarB03: .usect ".ebss", 1

 

It is also evidently impossible to pass a pointer to a ‘C’ variable into a ‘C’ callable assembly function (via XAR4) to then set the Data Page for that variable. For example, the ‘C’ callable assembly function below:

   short int Sum64Max(short int *words, unsigned short count);

will have the pointer to words in XAR4 but there is no instruction available to load the DP register using XAR4 as required such as:

   MOVW      DP, XAR4 ;set DP for page of given pointer. NO SUCH INSTRUCTION!!!

 

Also, it appears that there are no instructions available to allow one to access an array of variables of a Data Page. For example, there is no instruction available such as MOV @Var+AL, #0 in the code below:

VARSIZE: .set 64 ;maximum possible words in page

Var: .usect ".ebss", VARSIZE, 1 ;blocking flag = 1 to reset page boundary

_Test:

   MOV    AR5, #VARSIZE

   MOV    AL, #0

   MOVW   DP, #Var

LOOP64:

   MOV    @Var+AL, #0 ;write to location. NO SUCH INSTRUCTION!!!

   ADD    AL, #1      ;increment location

   BANZ   LOOP64, AR5--

   LRETR

but one can execute an instruction such as:

   MOV @Var+68, #0XFFFF ;valid instruction to write to location but is 4, not 68

 

One may also assume that one could use the instruction such as MOV @AL, AH, versus MOV @Var, AH, to access an array as in the code below:

 

VARSIZE: .set 64 ;maximum possible words in page

Var: .usect ".ebss", VARSIZE, 1 ;blocking flag = 1 to reset page boundary

_Test:

   MOVW  DP, #Var

   MOV   AL, #Var

   AND   AL, #0X3F

   MOV   AH, #0

   MOV   AR0, #VARSIZE

LOOP64:

   MOV   @AL, AH ;!!!@AL is not what is "at" AL but IS AL and is identical to MOV AL, AH

   ADD   AH, #1 ;increment value

   ADD   AL, #1 ;increment pointer

   BANZ  LOOP64, AR0--

   LRETR

 

However, one quickly learns that MOV AL, AH and MOV @AL, AH are the same operation and MOV @AL, AH is nothing at all like the instruction MOV @Var, AH. And there is also no instruction such as MOV *AL, AH as there is MOV *XAR4, AH.

Fortunately, Indirect Addressing can be used as follows:

_Test:

   MOVL  XAR4, #Var

   MOV   AH, #0

   MOV   AR0, #VARSIZE-1

LOOP64:

   MOV   *XAR4++, AH ;move and increment pointer

   ADD   AH, #1      ;increment value

   BANZ  LOOP64, AR0--

   LRETR

 

And, for initializing variables to the same value, how can Direct Addressing beat this?

_Test:

   MOVL  XAR4, #Var

   MOV   AH, #0

   RPT   #VARSIZE-1 || MOV *XAR4++, AH

   LRETR

 

Also evidently, the only way to Direct Address variables is if each variable of the page has a name assigned to it and it is not an array. For example, instead of simply having an array of variables as:

   Var: .usect ".ebss", 64, 1 ;blocking flag = 1 to reset page boundary

one must have each and every variable element named as, for example:

   Var01: .usect ".ebss", 1, 1 ;blocking flag = 1 to reset page boundary

   Var02: .usect ".ebss", 1

   Var03: .usect ".ebss", 1

   …

   Var62: .usect ".ebss", 1

   Var63: .usect ".ebss", 1

   Var64: .usect ".ebss", 1

 

TI urges “Extreme caution” when utilizing asm inline code in ‘C’ code.

Evidently, TI should also urge “Extreme caution” when utilizing Direct Addressing.

Don’t you agree?

 

If there is additional information about Direct Addressing that I am not aware of, please do not hesitate to indicate so. Any information would be greatly appreciated.

 

Thank you,

Tim

  • P.S. The code below demonstrates dangers of Direct Addressing when the size of a seemingly completely unrelated variable is changed. The code utilized is that in the example included in the TI SPRU430e document entitled 'TMS320C28x CPU and Instruction Set Reference Guide', section 5.4.

    ;Examples based on SPRU430e, section 5.4 example.

    ;VARXSIZE of 61 words causes Data Page break between VarC & VarD, breaking SPRU430e example

    ;VARXSIZE of 62 words causes Data Page break between VarB &  VarC, as SPRU430e assumes

    ;VARXSIZE of 63 words causes Data Page break between VarA & VarB, breaking SPRU430e example

    VARXSIZE: .set 61

    VarX:.usect ".ebss", VARXSIZE, 1 ;blocking flag = 1 to reset page boundary

    VarA:.usect ".ebss", 1

    VarB:.usect ".ebss", 1

    VarC:.usect ".ebss", 1

    VarD:.usect ".ebss", 1

    _DirectAdd:

    LCR  _InitVarsAL ;Initialize VarA=1, VarB=2, VarC=3, VarD=4, AL=0, and VarX elements = 0

    ;SPRU430e example below SHOULD result in: VarB = VarA = 1, VarD = VarA - VarC = -2

    ;SPRU430e example below FAILS for VARXSIZE = 61 with VarX[0] = -2 instead of VarD

    ;SPRU430e example below CORRECT for VARXSIZE = 62

    ;SPRU430e example below FAILS for VARXSIZE = 63 with VarX[0] = 1 instead of VarB

    MOVW DP,#VarA ;Load DP pointer with page value containing VarA

    ADD AL,@VarA  ;Add memory location VarA to register AL

    MOV @VarB,AL  ;Store AL into memory location VarB

    ;VarB is located in the same 64-word page as VarA

    MOVW DP,#VarC ;Load DP pointer with page value containing VarC

    SUB AL,@VarC  ;Subtract memory location VarC from register AL

    MOV @VarD,AL  ;Store AL into memory location VarD

    ;VarC is located in the same 64-word page as VarD

    ;VarC & D are in different pages than VarA & B

    ;Above is 6 cycles but may break if VARXSIZE changed

    LCR  _InitVarsAL ;Initialize VarA=1, VarB=2, VarC=3, VarD=4, AL=0, and VarX elements = 0

    ;SPRU430e example with 2 extra cycles CORRECT for any VARXSIZE ONLY because DP loaded to GUARANTEE that CORRECT variable is accessed

    MOVW DP,#VarA ;Load DP pointer with page value containing VarA (1 cycle)

    ADD AL,@VarA  ;Add memory location VarA to register AL (1 cycle)

    MOVW DP,#VarB ;Load DP pointer with page value containing VarB which COULD be different than A (1 cycle)

    MOV @VarB,AL  ;Store AL into memory location VarB (1 cycle)

    ;VarB is located in the same 64-word page as VarA

    MOVW DP,#VarC ;Load DP pointer with page value containing VarC (1 cycle)

    SUB AL,@VarC  ;Subtract memory location VarC from register AL (1 cycle)

    MOVW DP,#VarD ;Load DP pointer with page value containing VarD which COULD be different than C (1 cycle)

    MOV @VarD,AL  ;Store AL into memory location VarD (1 cycle)

    ;VarC is located in the same 64-word page as VarD

    ;VarC & D are in different pages than VarA & B

    ;Above is 8 cycles but will not break if VARXSIZE changed

    ;Initialize and do same process above but reliably (i.e. SAFELY)

    LCR  _InitVarsAL ;Initialize VarA=1, VarB=2, VarC=3, VarD=4, AL=0, and VarX elements = 0

    ;Code below result is always VarB = VarA = 1, VarD = VarA - VarC = -2 for any VARXSIZE:

    MOVL XAR0, #VarA ;Load XAR0 with VarA address (1 cycle)

    ADD  AL, *XAR0   ;Add memory location VarA to register AL (1 cycle)

    MOVL XAR0, #VarB ;Load XAR0 with VarB address (1 cycle)

    MOV  *XAR0, AL   ;Store AL into memory location VarB  (1 cycle)

    MOVL XAR0, #VarC ;Load XAR0 with VarC address (1 cycle)

    SUB  AL, *XAR0   ;Subtract memory location VarC from register AL (1 cycle)

    MOVL XAR0, #VarD ;Load XAR0 with VarD address (1 cycle)

    MOV  *XAR0, AL   ;Store AL into memory location VarD (1 cycle)

    ;Above is 8 cycles and will never break if VARXSIZE changed

    ;TI urges extreme caution when using inline assembly.

    ;That same caution should be urged when using Direct Addressing.

    LRETR

    _InitVarsAL: ;Initialize VarA=1, VarB=2, VarC=3, VarD=4, AL=0, and VarX elements = 0

    MOVL XAR0, #VarA

    MOV  *XAR0, #1

    MOVL XAR0, #VarB

    MOV  *XAR0, #2

    MOVL XAR0, #VarC

    MOV  *XAR0, #3

    MOVL XAR0, #VarD

    MOV  *XAR0, #4

    MOV  AL, #0

    MOVL XAR0, #VarX-1

    RPT #VARXSIZE

    || MOV *XAR0++, AL

    LRETR