gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > SWI 6 disabling an interrupt ?

#11296 - mathieu - Wed Oct 01, 2003 6:31 pm

Hello all !

I am coding a little sound system, which uses DMA1 and 2 (stereo sound), and timers 0 and 1. The synchronization of the system is made by an interrupt function hooked to timer1, thus it is not necessary to call something every vblank - once initialized, the system works by itself.

Everything was fine until I tried to call somewhere in my main code, while the soundsystem is running, the following thumb function :

u32 div(u32 num, u32 den) {
u32 result;
__asm ("mov r0, %[num]
mov r1, %[den]
swi #6
mov %[result], r3
" : [result] "=r" (result) : [num] "r" (num), [den] "r" (den) :
"r0", "r1", "r2", "r3");
return result;
}

And as soon as I call that, the sound output stop working and makes "clicks", just as if the interrupts were inhibited.

Are there things one should care about before calling a SWI instruction ?

Any clue would be greatly appreciated :).

Best regards,

mathieu

#11298 - tepples - Wed Oct 01, 2003 7:25 pm

A few problems I can see:
  • swi 6 is division. Division by zero is undefined.
  • swi 6 is signed division, and your function seems to take unsigned arguments.
  • It'd probably be better to write the divide function in assembly language rather than in C with inline assembly.


Here's an excerpt from my math.s that addresses all three of these. It was designed for coordinate projection, so it does something useful with division by zero rather than crashing; namely, it returns INT_MAX.
Code:

@ int div(int num, int den)
@ Divide two signed integers.

.THUMB
.THUMB_FUNC
.ALIGN
.GLOBL  div

div:
  cmp r1, #0
  beq 0f
  swi 6
  bx lr
0:
  ldr r0, =0x7fffffff
  bx lr

_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#11300 - mathieu - Wed Oct 01, 2003 7:45 pm

So, you're right for unsigned arguments - I forgot about that and it can be quite a problem.

However, I tested the case of the division by 0, which should be the only case of swi 6 going in an infinite loop.

I set in my call the "den"(for denominator) value to 1. And it still does the same thing --> the GBA suddenly makes "clicks" instead of sound.

Thus my assumption of SWI 6 doing something with interrupts...

#11303 - mathieu - Wed Oct 01, 2003 11:51 pm

Well, I know now what actually happened.

I was building my files using the gcc 3.2 -mthumb-interwork flag, thinking (with the "mthumb" written) that it was generating Thumb code.

Well, as a matter of fact, it was generating arm code.

And "swi #6" in arm code hangs, logically.

I think it is strange to use a "-mthumb -mthumb-interwork" double-flag to create thumb code. I'd rather see something like "-mthumb-interwork" and "-marm-interwork" to specify whether I want an Thumb or ARM binary code.

But well, it doesn't work this way...

Best regards,

Mathieu

#11306 - poslundc - Thu Oct 02, 2003 12:33 am

Sort of shooting off on a tangent here... I haven't really delved that much into ASM yet, but it's only a matter of time before I'll have to in order to optimize the crap I'm doing. And while I'm not shy about assembly-level coding, knowing the correct keywords to use, etc. when faced with all of the different configurations and compilers out there as well as coding for two different processors is enough to make me tug at my collar with some apprehension.

So on that note... if I call gcc on an assembler file, what determines if it generates ARM or Thumb code? Is it just placing a ".arm" statement at the beginning of the file? Likewise, is ".iwram" all it takes to load it into IWRAM?

I understood the -mthumb-interwork flag to tell the compiler that you want your code to be callable from thumb code, but does it therefore also automatically assume that you must be writing ARM code if you want that?

Thanks,

Dan.

#11310 - DekuTree64 - Thu Oct 02, 2003 3:37 am

The default for C files is -marm. You have to specifically say -mthumb if you want to generate THUMB code, and then -mthumb-interwork is a whole other option completely, which is poorly named. It would be nicer to just say -interwork, but I guess it doesn't really matter now that you know the difference.
And yes, just use .arm and .thumb to switch instruction sets in ASM files. To put code in IWRAM though, you need to use
.section .iwram, "ax", %progbits
and to switch back to normal ROM code, just put
.text
I'm not really sure why you don't have to do the whole .section deal with .text, but I got an error when I did, so whatever works I guess.
Don't forget to put an .align 4 before actually writing ARM code though.
ALso, pretty much none of the flags do anything to an assembler file. For example, interworking is just in the way you call functions, so if you want to support it, be sure to use
ldr rTemp, =FuncName
mov lr, pc @or mov r14, r15. r15 points 2 instructions ahead, so this will return to the instruction after the bx
bx rTemp
instead of just bl FuncName. But if you're going to the trouble to write in ASM, you can keep track of what language your functions are in and always bx to the ones in the other language, and bl to the ones that use the same language, because it's much faster and easier.
And always return with bx lr, not mov pc, lr. They're the same speed anyway.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#11334 - torne - Thu Oct 02, 2003 8:31 pm

DekuTree64 wrote:
To put code in IWRAM though, you need to use
.section .iwram, "ax", %progbits
and to switch back to normal ROM code, just put
.text
I'm not really sure why you don't have to do the whole .section deal with .text, but I got an error when I did, so whatever works I guess.

The reason you don't have to do this is because .text is a shorthand for .section text, "ax", %progbits. The section's name is text, not .text, if you refer to it in a .section directive (the dot prefix is to make it into an assembler directive, not part of the name).

The bits about interworking in asm are accurate; read the ARM/Thumb Procedure Call Standard (on ARM's website) and/or my various posts explaining this before for more information on how assembly function calls should work. It's unfortunate that the GBA's processor, the ARM7, implements the ARMv4 instruction set, as the ARMv5 set has both a blx instruction (branch with link and exchange, does the same as bx but sets lr for you too), and sets cpu modes on a PC load or pop (avoids having to pop lr into a temp register and bx to it; can just pop lr directly into pc). =)

#11365 - funkeejeffou - Fri Oct 03, 2003 8:39 am

There are known problems when using interrupts and bios functiuns:
Quote:
In some cases the BIOS may allow interrupts to be executed from inside of the SWI procedure. If so, and if the interrupt handler calls further SWIs, then care should be taken that the Supervisor Stack does not overflow.
from the GBATEK doc.

The reason is that an interrupt might occur while the code is running a bios call, and a interrupt calls the bios. Me too had problems using both of them so you can try this :
Before any bios calls disable the interrupts and enable them back after ou are out. That should fix it (I hope you do not have too much divisions though...).
You can get ASM division code from www.devrs.com wich runs as fast as the one from the BIOS, and therefore you will call this code. Note that this code will certainly run slowerly than the bios one if the result from your division is supposed to be very high(26684321/31). Otherwise this code will beat the BIOS one (as for 655/69).
Finally, I've done some code under gcc and sometime, even if you think your code is thumb or arm, better be sure. So try replacing swi 0x6 by swi 0x60000(ARM).

Hope this helps

#11369 - torne - Fri Oct 03, 2003 4:23 pm

Alternatively, just point the supervisor mode stack pointer to somewhere with more space, if you have memory to spare. This will greatly decrease the chance that you run out.