16 bit LR move

Im trying to copy the LR to R0 to return the calling function’s address to some other function, but Im coming with some issues. Im modifying my division libraries to detect a divide by zero and return the calling function’s address back to another function to record the initial division’s address

I have two similar assembly functions, one 32 bit which works fine, and a 16 bit which does not. The 32 bit div function looks something like this:

============

	.state32
	
	.global U_DIV
	.global U_MOD
        .global _div_zero
        

dvs	.set	r2		; WORK COPY OF THE DIVISOR (SHIFTED)
quo	.set	lr		; WORK COPY OF THE QUOTIENT
osp .set    r3
	
U_DIV:	
U_MOD:	
	STMFD	sp!, {dvs, lr}		; SAVE CONTEXT

	MOVS	dvs, r1			; CHECK FOR DIVISION BY ZERO
	BEQ	div_by_zero		
  <rest of code>


div_by_zero:

	MOV a1, LR                         ; Copy LR to A1 to return to div_zero
	BL _div_zero                       ; Call to div_zero
	MOV r0, #0 ; 
	LDMFD	sp!, {dvs, pc}		;
	
	.end

============

This works fine. My div_zero function gets the address stored in the LR and I can do what I want with it. I try to do something similar with the 16 bit and the same code crashes. Unfortunately, I dont have an emulator, so Im trying this blind :confused:

The 16 bit code looks something like this

============

	.state16
	.align			; REQUIRED SO ADD PC IS WORD ALIGNED BELOW

	.global U$DIV
	.global U$MOD
	.global _div_zero


dvs	.set	r2		; WORK COPY OF THE DIVISOR (SHIFTED)
quo	.set	r3		; WORK COPY OF THE QUOTIENT
tmp	.set    r4


U$DIV:	
U$MOD:  PUSH    {r2-r4} 	        ; SAVE CONTEXT
 
	MOV	dvs, r1			; INITIALIZE THE DIVISOR (SHIFTED)
        BEQ     div_by_zero    
    <rest of code>

div_by_zero:
		
	MOV A1, LR	
	BL _div_zero
	MOV	r0, #10			; DIVIDE BY ZERO RETURNS ZERO
        POP     {r2-r4}                 
	MOV	pc, lr			

	.end

=====================

resulting list file

=====================

     37 00000000           U$DIV:  
      38 00000000 B41C      U$MOD:  PUSH    {r2-r4}          
      39                     
      40 00000002 1C0A              MOV     dvs, r1                 
      41 00000004 D044              BEQ     div_by_zero          
      42      

   126 00000090           div_by_zero:
     127                    
     145                                    
==>     146 00000090 4670              MOV A1, LR      
==>     147                                                            
==>     148 00000092 F7FF!             BL $div_zero
==>         00000094 FFB5     
     149                    
     152                            
     153 00000096 200A              MOV     r0, #10                 
     154 00000098 BC1C              POP     {r2-r4}                 
     155                            
     157                    
     158 0000009a 46F7              MOV     pc, lr                  
     159                    
     160                            .end

=====================

According to the PDF I have TMS470R1x User’s Guide

A value may be transferred from a register in the range R0-R7 (a Lo register) to a Hi register, and from a Hi register to a Lo register, using special variants of the MOV instruction. Hi register values can also be compared against or added to Lo register values with the CMP and ADD instructions. See Section 5.5, Format 5: Hi register operations/branch exchange, 5-14.

Is this the proper usage of transferring a HI reg (LR/R14) to a LO reg (A1)? That PDF has the opcode for MOV but doesnt say what the hex output for this “special” mode should be so I cant cross reference this with my list file to see if its generating what I think it should.

Am I going about this the right way? Is this how to pass the LR back to a function in 16 bit?

There may be other issues relating to 16-bit/Thumb mode (that’s not something I’ve ever worked with), however your 16-bit code is guaranteed to crash because lr is overwritten when you do the BL _div_zero - the return address from the division routine no longer exists. The 32-bit version of the code pushed lr on the stack, so you were able to return by popping that value into pc. You will need to save/restore lr yourself for the 16-bit version.

Ah, that sounds logical and explains exactly what Im seeing. Ill give that a go and see if it helps