Difference between revisions of "GetVRAMAddress"

From WikiPrizm
Jump to navigationJump to search
m
Line 1: Line 1:
== Synopsis ==
+
{{syscall
'''Syscall:'''0x01E6
+
| index = 0x01E6
 +
| signature = void *GetVRAMAddress(void)
 +
| returns = A pointer to the system's [[Display|VRAM]].
 +
| comments = While this function currently always returns 0xA8000000, it may change in the future (although this is unlikely).  The VRAM address has however changed between calculator models, so using this syscall can help portability or with detecting the calculator model.
  
'''Function declaration:'''void*GetVRAMAddress(void);
+
If speed is a concern, it will be slightly faster to use a hard-coded (preprocessor define) address for VRAM.  If portability is a concern, one should use this function.  For cases where both speed and portability are important, it is suggested that the program check the return value of this function against the hard-coded value to ensure it will function normally.
 +
}}
  
=== Inputs ===
+
=== Speed proof ===
 +
The following program proves that using a hard-coded VRAM address will perform better (built with GCC 4.7.0):
 +
<nowiki>#define VRAM ((unsigned short *)0xA8000000)
 +
static unsigned short *vram;
  
None
+
// VRAM location determined at runtime
 +
void dynamic() {
 +
    vram[0] = 0;
 +
}
  
=== Outputs ===
+
// Hard-coded VRAM location
A void* pointer to the address of VRAM.
+
void hard() {
 +
    VRAM[0] = 0;
 +
}
  
== Comments ==
+
int main() {
 +
    vram = GetVRAMAddress();
  
The return address is currently a constant address of 0xA8000000, but has the potential to be changed in the future, while very unlikely.  If nothing else, this syscall is useful as it can help distinguish between different calc models, and can help with providing compatibility with future OS versions and other models.  It is suggested that if you call it though, you save it in a variable at the beginning of a program, because using it to constantly get the VRAM address may slow down your program slightly.
+
    dynamic();
 +
    Bdisp_PutDisp_DD();
 +
    hard();
 +
    Bdisp_PutDisp_DD();
  
[[Category: Syscalls]]
+
    return 0;
 +
}</nowiki>
 +
Running objdump on the generated binary (built with GCC <tt>-Os</tt>), we can see there is a difference:
 +
<nowiki>$ sh3eb-elf-objdump -rd vramtest.o</nowiki>
 +
 
 +
<nowiki>Disassembly of section .text:
 +
 
 +
00000000 <_dynamic>:
 +
  0:  d1 02          mov.l  c <_dynamic+0xc>,r1    ! 0 <_dynamic>
 +
  2:  e2 00          mov    #0,r2
 +
  4:  61 12          mov.l  @r1,r1
 +
  6:  00 0b          rts
 +
  8:  21 21          mov.w  r2,@r1
 +
  a:  00 09          nop
 +
  c:  00 00          .word 0x0000
 +
                        c: R_SH_DIR32  .bss
 +
        ...
 +
 
 +
00000010 <_hard>:
 +
  10:  d1 01          mov.l  18 <_hard+0x8>,r1      ! a8000000
 +
  12:  e2 00          mov    #0,r2
 +
  14:  00 0b          rts
 +
  16:  21 21          mov.w  r2,@r1
 +
  18:  a8 00          bra    fffff01c <_hard+0xfffff00c></nowiki>
 +
It is possible that more extreme optimization options (<tt>-O2</tt> or higher, [[GCC#LTO|<tt>-flto</tt>]]) will reduce or even completely remove the advantage of the hard-coded address, but the dynamic version cannot ever be faster.

Revision as of 12:28, 22 May 2012


Synopsis

Header: Not documented
Syscall index: 0x01E6
Function signature: void *GetVRAMAddress(void)

Returns

A pointer to the system's VRAM.

Comments

While this function currently always returns 0xA8000000, it may change in the future (although this is unlikely). The VRAM address has however changed between calculator models, so using this syscall can help portability or with detecting the calculator model.

If speed is a concern, it will be slightly faster to use a hard-coded (preprocessor define) address for VRAM. If portability is a concern, one should use this function. For cases where both speed and portability are important, it is suggested that the program check the return value of this function against the hard-coded value to ensure it will function normally.

Speed proof

The following program proves that using a hard-coded VRAM address will perform better (built with GCC 4.7.0):

#define VRAM ((unsigned short *)0xA8000000)
static unsigned short *vram;

// VRAM location determined at runtime
void dynamic() {
    vram[0] = 0;
}

// Hard-coded VRAM location
void hard() {
    VRAM[0] = 0;
}

int main() {
    vram = GetVRAMAddress();

    dynamic();
    Bdisp_PutDisp_DD();
    hard();
    Bdisp_PutDisp_DD();

    return 0;
}

Running objdump on the generated binary (built with GCC -Os), we can see there is a difference:

$ sh3eb-elf-objdump -rd vramtest.o
Disassembly of section .text:

00000000 <_dynamic>:
   0:   d1 02           mov.l   c <_dynamic+0xc>,r1     ! 0 <_dynamic>
   2:   e2 00           mov     #0,r2
   4:   61 12           mov.l   @r1,r1
   6:   00 0b           rts
   8:   21 21           mov.w   r2,@r1
   a:   00 09           nop
   c:   00 00           .word 0x0000
                        c: R_SH_DIR32   .bss
        ...

00000010 <_hard>:
  10:   d1 01           mov.l   18 <_hard+0x8>,r1       ! a8000000
  12:   e2 00           mov     #0,r2
  14:   00 0b           rts
  16:   21 21           mov.w   r2,@r1
  18:   a8 00           bra     fffff01c <_hard+0xfffff00c>

It is possible that more extreme optimization options (-O2 or higher, -flto) will reduce or even completely remove the advantage of the hard-coded address, but the dynamic version cannot ever be faster.