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.

What is wrong with my software interrupt SWI vector branch instruction? Why does it branch too far?

  1. I installed  a branch to softwareDispatch at the SWI vector #8. 
  2. When SWI #0x1 is called it jumps to 0x08 as I expected and CPSR mode = 0b10011 ( supervisor )
  3. Why does the branch instruction EA00007C jump very far to location 020007e4?
  4. I expected it to jump to softwareDispatch @ 00000200

Here is what it looks like as I single-step through the debugger:

=>800028f0:   EF000001 SWI           #0x1
  ...
  ...
  ...
  00000000:   EF3D7039 SWI           #0x3D7039
  00000004:   C8D346BE LDMGTFD       R3, {R1-R5, R7, R9-R10, R14}^
=>00000008:   EA00007C B             softwareDispatch
  0000000c:   8ABD2FBC BHI           0xFEF4BF04
  00000010:   0E439F7D MCREQ         P15, #0x2, R9, C3, C13, #0x3
  00000014:   D589E967 STRLE         R14, [R9, #0x967]
  00000018:   9A17D020 BLS           0x005F40A0
  0000001c:   82CF6450 SBCHI         R6, PC, #0x50000000
  ...
  ...
  ...
=>020007e4:   E2877002 ADD           R7, R7, #0x2
  020007e8:   E3550009 CMP           R5, #0x9
  020007ec:   8A00000B BHI           0x02000820
  020007f0:   E28FC000 ADD           R12, PC, #0x0
  020007f4:   E79CF105 LDR           PC, [R12, R5, LSL #2]
  020007f8:   0200098C ANDEQ         R0, R0, #0x230000
  020007fc:   02000950 ANDEQ         R0, R0, #0x140000
  02000800:   02000914 ANDEQ         R0, R0, #0x50000
  ...
  ...

I expected the branch instuction EA00007C to end up here @ 0x200. What happened?

57        void softwareDispatch(int softwareInterruptNumber, uint32_t * regs) {
          softwareDispatch:
=>00000200:   E92D400E STMFD         R13!, {R1-R3, R14}
  00000204:   E58D1004 STR           R1, [R13, #0x4]
  00000208:   E58D0000 STR           R0, [R13]
63        	asm("    nop");
          label1:
  0000020c:   E1A00000 MOV           R0, R0

My eventual goal is to switch to supervisor mode so I can enable ARM interrupts in CPSR.

/// Updates contents of 'vector' to contain branch instruction
/// to reach 'routine' from 'vector'. Function return value is
/// original contents of 'vector'.
/// NB: 'Routine' must be within range of 32MB from 'vector'.
///
/// Usage:
/// \code
/// unsigned *irqvec = (unsigned *)0x18;
/// Install_Handler ((unsigned)IRQHandler, irqvec);
/// \endcode
///
/// \remarks routine must be located within 32Mbtes of the vector
unsigned installHandler(unsigned routine, unsigned *vector) {
	unsigned oldvector;
	// routine is the pointer point to the IRQ handler.
	// shift right 2 is for address word aligned.
	//  subtract 8 is due to the pipeline
	// since PC will be fetching the 2nd instruction
	// after the instruction currently being executed.
	unsigned newVector = ((routine - (unsigned) vector - 8) >> 2);
	if (newVector & 0xff000000) {
		printf("*** Error handler greater than 32MBytes from vector\n");
		return 0;
	}
	// to implement the instruction B <address>
	// 0xea is the Branch operation for "branch always" (BAL)
	newVector = 0xea000000 | newVector;
	oldvector = *vector;
	*vector = newVector;
	return oldvector;
}

	// Install the softwareInterruptDispatcher so we cchange modes to enable interrupts
	unsigned *irqSwiVector = (unsigned *) (8);
	unsigned softwareInterruptHandlerFunctionPointer = (unsigned) softwareDispatch;
	oldVector = installHandler(softwareInterruptHandlerFunctionPointer,
			irqSwiVector);

-Ed

CCS v5.5

DM6446