Dispint Irq


The usual uses for registers are as follows:

R0 - R3 - Working registers & function call parameters (No need to save across function calls)
R4 - R9 - Working registers (Must be saved across function calls)

R10 SP Stack Limit
R11 FP Frame pointer
R12 IP Scratch Register
R13 SP Stack Pointer
R14 LR Link Register
R15 PC Program Counter

Although you can use any register as your stack, R13 is the normal, and if you want compatibility with GCC, it should be the one you use.

The BL (Branch with Link) instruction will copy the address of the next instruction to R14 before calling the function. Exceptions (such as interrupts) copy the current contents of R15 to R14 in the bank of the exception handler. This may or may not be the address of the next instruction, depending on the type of exception.

Setting up R13 on startup rather than each time the interrupt occurs will save you an instruction, and thus give you less interrupt latency to get to your proper code, but setting it up everytime on interrupt entry will always ensure it points to a valid place (ie. you can then exit your interrupt without restoring R13 to the default value).

Personally, I prefer to setup R13 once in the startup code for each processor state (SVC, IRQ, etc), and leave it at that.
 
Thanks for that,i'll try to burn that into my brain. That stack bug of mine must have been messing with my semiphore code as its all working 100% now. :)
 
Squidge posted on May 27 2006 at 11:39 AM said:
R0 - R3 - Working registers & function call parameters (No need to save across function calls)

Just to make sure, if I use r0 - r3 in some inline asm I don't need to restore them?
 
Last edited by a moderator:
MadDog posted on May 28 2006 at 05:23 AM said:
Squidge posted on May 27 2006 at 11:39 AM said:
R0 - R3 - Working registers & function call parameters (No need to save across function calls)

Just to make sure, if I use r0 - r3 in some inline asm I don't need to restore them?
In general, this is not true. If you write an assembly language function you can use those registers in the function as you like without restoring them because when a function call is made it is assumed that those registers are saved. Consider the following C code:

Code:
extern int test2();

int test(int a)
{
  return a + test2();
}
When compiled with gcc, it produces this:
Code:
test:
  stmfd  sp!, {r4, lr}
  mov  r4, r0
  bl  test2
  add  r0, r0, r4
  ldmfd  sp!, {r4, pc}
Notice how the compiler moves the parameter 'a' from r0 to r4 before calling 'test2' -- because r0 might get clobbered in test2. Also, since r4 is getting clobbered now, it has to be saved at the beginning and restored at the end.

Now consider this code:
Code:
int test(int a, int b)
{
  asm volatile ("mov r0, #0");
  return a+b;
}
This produces the following code:
Code:
test:
  mov r0, #0
  add  r0, r0, r1
  bx  lr
See how the inline assembly screws up the result by clobbering r0 and the compiler makes no effort to get around it. If I change the code to add a clobber list:
Code:
int test(int a, int b)
{
  asm volatile ("mov r0, #0\n" :::"r0");
  return a+b;
}
Now the compiler knows that I'm wrecking r0 so the code produced is now:
Code:
test:
  mov r3, r0
  mov r0, #0
  add	r0, r3, r1
  bx	lr
Since r0 will be clobbered the compiler moves its value to r3 for later use.

So to answer your original question, in general you DO need to restore them when you use inline assembler (unless your "inline" code is an entire function), but you can use a clobber list to tell the compiler to do that for you.
 
Last edited by a moderator:
Wow, DZZ's post is much more indepth than my one liner I tried to post, but then found out my connection had died :eek:

Yes, R0-R3 are reserved for function parameters and no other reason I'm aware of, so you'll need to save them in every other case.
 
Thats a really good discription, thanks. :) Maybe that could be added to the Wiki. Thanks Dzz. What I need to do is to confirm the problems I was having with the clobber list was the compiler and not a bug of mine.
 
MadDog posted on May 26 2006 at 01:00 PM said:
"IRQ:"//IRQ interrupt handler.
"stmfd sp!,{r0-r3} \n"
""//Reset the interrupt so we can get another one when its done.
"ldr r0,=0xbe004500 \n"
"ldr r1,[r0] \n"
"orr r1,r1,#1 \n"
"str r1,[r0] \n"
"ldr r0,=0xbe004510 \n"
"ldr r1,[r0] \n"
"orr r1,r1,#1 \n"
"str r1,[r0] \n"
""//Inc our frame count var.
"mov r0,#0x00800000 \n"
"ldr r1,[r0] \n"
"add r1,r1,#1 \n"
"str r1,[r0] \n"
""//And done, return.
"ldmfd sp!,{r0-r3} \n"
"subs pc,r14,#4 \n"
""//All unhandle interupts end up here, could be intresting.

Does DPC_INTR not need to be cleared (set bit 2), in the isr above?

Counting interrupts I get about 111 per second. In theory that means 111 frames per second if you can create and move data that fast.

A fast memcpy from cached ram to the video page can copy 116 pages per second. Using LDM/STM pairs 4 words (16 bytes) at a time. This is on the 940.

And if I have my math right that leaves 77,000 clock cycles to draw something (200mhz). There are 76,800 pixels so you cannot draw or change every one, but you could change some of them each frame.

Do these numbers sound reasonable?
 
Last edited by a moderator:
Back
Top