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 > Copy to EWRAM

#23988 - ProblemBaby - Mon Jul 26, 2004 2:03 am

Hi

Now iam trying to copy code to EWRAM but no$gba give me fatal error
the rom-image has crashed.

The thing iam trying to do is...
Ive a Multiboot program (its really small)
and I want to copy a function to a another place in ewram.
(plz if you now how do it, dont just repost a: WHY?!?!?)

well my code goes like this:
Code:

u16 *EWRAM        = (u16 *)0x2000000;
   void (*ewramcode)();
   ewramcode = 0x2010000; // 0x10000 to be sure that i dont mess with the other data
   u32 Address = 0;
// Later I will check for the branch instead
   while (Address < 100)
// well, the function cant be bigger then 100 *sizeof(u16) bytes
{
      EWRAM[0x10000 + Address] = ((u16 *)MyFunction)[Address];
      Address++;
   }
   ewramcode(); // when I do this i got error


Thanks in advance

#23994 - DekuTree64 - Mon Jul 26, 2004 2:48 am

The copying looks fine. Is the function compiled as THUMB? If so, then the problem is that you're getting switched over to ARM mode without knowing it. Because you can only do a regular branch to a PC-relative location, and function pointers are loaded from memory into registers, the compiler has to use bx.
Normally, when you set a function pointer to the address of a function (as opposed to a direct value like 0x2010000), it can check wether that function is written in ARM or THUMB and set the THUMB flag accordingly. The lower bit of the address in the register you're bx'ing to is the THUMB flag, so the solution here is to set it by hand. Set the function pointer to 0x2010001 and see if it works.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#23999 - ETkoala - Mon Jul 26, 2004 7:56 am

you should try with other emu (for example: visualboy advance).
i hear that no$gba look the header before run.
be sure that the game isn't in a zip file (no$gba don't support zip)

#24001 - torne - Mon Jul 26, 2004 11:30 am

DekuTree64: No, you can branch to an absolute location just fine without using bx:
Code:
mov lr, pc
mov pc, register_with_address

GCC should happily generate this code when neccecary. Try disassembling the copying/calling function to see how it's calling the copied function - if it's doing bx then you do need to add the low bit to the address, but complaining to the maintainers would be in order; it's *very* silly for a call of this form to switch modes if it doesn't know either way.

I would be more worried about the contents of the function; is it position-independant?

#24005 - ProblemBaby - Mon Jul 26, 2004 1:01 pm

Ive tried a lot of different things acoording to what you have replayed
but I really cant get it to work either with no$gba, VBA or MappyVM.

Maybe someone can show me a working example?

#24006 - ProblemBaby - Mon Jul 26, 2004 1:33 pm

Maybe it is possible to make a function putted at 0x2010000
and then overwrite it? but I dont know how but maybe that could be a solution

#24007 - poslundc - Mon Jul 26, 2004 1:36 pm

torne wrote:
DekuTree64: No, you can branch to an absolute location just fine without using bx:
Code:
mov lr, pc
mov pc, register_with_address

GCC should happily generate this code when neccecary. Try disassembling the copying/calling function to see how it's calling the copied function - if it's doing bx then you do need to add the low bit to the address, but complaining to the maintainers would be in order; it's *very* silly for a call of this form to switch modes if it doesn't know either way.


I can't access my copy of the ARM documentation from work. Does anyone know if this style of branching can switch processor modes using the LSB?

For that matter, do any of the other branching techniques (B and BL, LDR and LDM to the PC, and I suppose any other ALU ops to the PC) permit an instruction set exchange, or just BX?

Dan.

#24012 - torne - Mon Jul 26, 2004 4:18 pm

poslundc wrote:
I can't access my copy of the ARM documentation from work. Does anyone know if this style of branching can switch processor modes using the LSB?

On the ARMv4 architecture, the LSB is processed when setting the program counter - mov, ldr and ldm will all set the CPU mode correctly. However, the ARM7 is an ARMv3 processor, and the ARMv3 only obeys the LSB during the BX instruction. This means that an interworking return on the GBA has to pop the link register value into a temporary register, then bx to that register, rather than being able to pop it directly into the program counter. Unless you write interworking-capable code in assembler, of course, this is done for you by the compiler. (I say a temporary register because in Thumb mode, the pop instruction cannot pop into LR, and another register must be used; in ARM mode, you can just pop into LR and then bx to LR - this actually makes a Thumb interworking return really, really unpleasant).

B and BL never generate an instruction set switch on either architecture; it is up to the linker to automatically insert shims between functions that call each other in this way that have differing instruction sets; GNU ld does this correctly in devkitarm/devkitgba, which is why this normally works. As it's done by the linker, you can even rely on this behaviour when coding in assembly.

#24028 - ProblemBaby - Mon Jul 26, 2004 8:26 pm

Here is my code:
Code:

.align
.section .text

.thumb_func
.global DrawLine
DrawLine:
   @ St?ller in DISPCNT
   LDR r0, =0x4000000
   LDR r1, =0x403
   STR r1, [r0]
   
   @ Ritar en r?d linje p? rad 5
   LDR r0, =0x6000960
   LDR r1, =0x1F
   LDR r2, =240
   label1:
   STRH r1, [r0]
   ADD r0, r0, #2
   SUB r2, r2, #1
   CMP r2, #0
   BNE label1
   hej:
   B hej

.thumb_func
.global CopyAndRun
CopyAndRun:
   @ Lagrar funktionen i EWRAM 0x2001000
   LDR r0, =DrawLine
   LDR r1, =0x2001000
   LDR r2, =0x100
   Copy:
   LDRB r3, [r0]
   STRB r3, [r1]
   ADD r0, r0, #1
   ADD r1, r1, #1
   SUB r2, r2, #1
   CMP r2, #0
   BNE Copy
   
   @ K?r Funktionen
   LDR r1, =0x2001000
   MOV pc, r1
   
   BX lr


Can someone see an error??

#24060 - DekuTree64 - Tue Jul 27, 2004 7:16 am

Ah, found it. The .thumb_func directive tells the linker that whenever it sees that symbol name, to set the lower bit of it as the THUMB flag, so for example, that ldr r0, =DrawLine would have the flag set so if you bx to it, you will be switched into THUMB state. However in this case, you're copying one byte at a time, so having the lower bit set means that you're copying the second half of the first instruction, and then the first half of the second instruction, into the first halfword of the destination. Of course the instructions that you will end up with are then completely wrong, so it goes off into the great beyond never to return.

Solution: replace that .thumb_func with plain .thumb (might give you problems if you try to call the function from C code), or subtract one from r0 after the ldr (wastes a cycle, and 2 bytes for the instruction. I'd go with this way for general purpose reliability).
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#24087 - ProblemBaby - Tue Jul 27, 2004 7:18 pm

Thanks a lot man!!

by the way, is it somehow possible to force a function or/and data to be placed last in ewram (in my case). I mean that after that it should be only junk no data or code..