Line 36 is the last line of the asm block below:
asm ( "@ MOV R0, %0\n" "@ MOV R1, %1\n" "@ MOV R2, %2\n" "swi 3\n" : : "r" (irq), "r" (isr), "r" (pri) );
I think the code was written for GCC not ARM C. How should this be written correctly using Keil compiler please
Thanks, David
Hello David,
It is difficult to answer this without the full context - inline assembler code depends on the C code around it.
The following builds for me with armcc:
int foo(){ int r0, r1, r2; __asm{ MOV r0, 0 MOV r1, 1 MOV r2, 2 SWI 3 } return (r0+r1+r2); }
Yes I understand:
/* Register an ISR */ void RegisterIrq ( int irq, void(*isr)(void), int pri ) { asm ( "@ MOV R0, %0\n" "@ MOV R1, %1\n" "@ MOV R2, %2\n" "swi 3\n" : : "r" (irq), "r" (isr), "r" (pri) ); }
I don't believe it's adding r0-R2 they get passed into the SWI invocation:
EXPORT SWI_Handler PRESERVE8 SWI_Handler MRS IP, SPSR TST IP, #B_Thumb ; Check caller's state, ARM or Thumb LDRNEH IP, [LR, #-2] ; Get swi instruction code (in Thumb state) LDREQ IP, [LR, #-4] ; Get swi instruction code (in ARM state) AND IP, #0xFF ; Get swi comment field (lower 8 bit) CMP IP, #7 ; Check range LDRLO PC, [PC, IP, LSL #2] ; Jump to each service function when code is valid MOVS PC, LR ; Otherwise return DCD irq_disable ; 0 Disable IRQ DCD irq_enable ; 1 Enable IRQ DCD clear_vect ; 2 Clear ISRs DCD reg_irq ; 3 Register vector address for IRQ DCD sel_fiq ; 4 Select FIQ interrupt DCD load_fiq ; 5 Load FIQ shadow regs from memory DCD store_fiq ; 6 Store FIQ shadow regs to memory ; ; Omitted ; reg_irq ; Register an IRQ CMP R0, #32 ; Range check MOVCSS PC, LR LDR IP, =(LPC_BASE_VIC+VIC_VectAddr0) STR R1, [IP, R0, LSL #2] ; Set VICVectVectAddr<n> LDR IP, =(LPC_BASE_VIC+VIC_VectPriority0) STR R2, [IP, R0, LSL #2] ; Set VICVectPriority<n> MOV R1, #1 MOV R1, R1, LSL R0 LDR IP, =LPC_BASE_VIC LDR R2, [IP, #VIC_IntSelect] ; Clear corresponding bit in the VICIntSelect BIC R2, R1 STR R2, [IP, #VIC_IntSelect] STR R1, [IP, #VIC_IntEnable] ; Enable corresponding interrupt MOVS PC, LR ; ; omitted ;
/* Register an ISR */ void RegisterIrq ( int irq, void(*isr)(void), int pri ) __asm{ SWI 3 } }
This is what was generated:
31: { 32: // asm ( 33: // "@ MOV R0, %0\n" 34: // "@ MOV R1, %1\n" 35: // "@ MOV R2, %2\n" 36: // "swi 3\n" : : "r" (irq), "r" (isr), "r" (pri) 37: // ); 38: __asm{ 0x00002CD4 E92D4070 STMDB R13!,{R4-R6,R14} 0x00002CD8 E1A04000 MOV R4,R0 0x00002CDC E1A05001 MOV R5,R1 0x00002CE0 E1A06002 MOV R6,R2 39: SWI 3 40: } 0x00002CE4 EF000003 SWI 0x00000003 41: } 0x00002CE8 E8BD4070 LDMIA R13!,{R4-R6,R14} 0x00002CEC E12FFF1E BX R14
I deleted interrupt.c and changed interrupt.h to read:
__swi(0) void IrqDisable (void); /* Disable all IRQ */ __swi(1) void IrqEnable (void); /* Enable all IRQ */ __swi(2) void ClearVector (void); /* Unregister all ISRs */ __swi(3) void RegisterIrq (int irq, void(*isr)(void), int pri); /* Register an ISR as IRQ */ __swi(4) void SelectFiq (int irq); /* Switch an interrtupt source as FIQ */ __swi(5) void LoadFiqRegs (long *regs); /* Load shadow regs R8-R12 from memory */ __swi(6) void StoreFiqRegs (long *regs); /* Store shadow regs R8-R12 to memory */
That seems to have a) resolved any issues with asm format and b) simplified the code!!
I added those values so that they would not be optimized away. Inline assembler behaves quite different to the 'real' assembler.