summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/gba/start/start.S
blob: 99dfc9a0345a8b9d3a5dc334c1df0d43e2921bd3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
/**
 *  @file start.S
 *
 *  RTEMS entry point.
 */
/*
 *  RTEMS GBA BSP
 *
 *  Copyright (c) by Jeff Frohwein.
 *
 *  Copyright (c) 2003, Jason Wilkins.
 *
 *  Copyright (c) 2004  Markku Puro <markku.puro@kopteri.net>
 *  based on crt0.S v1.28 by Jeff Frohwein
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.org/license/LICENSE.
 */

/*****************************************************************************
 * This source file is based on work by Jeff Frohwein and Jason Wilkins
 *****************************************************************************
 *****************************************************************************
 * crt0.S v1.28 by Jeff Frohwein
 * :
 * This file is released into the public domain for commercial
 * or non-commercial usage with no restrictions placed upon it.
 *****************************************************************************
 * Copyright 2003, Jason Wilkins.  This source code is free for any use except
 * that this copyright notice and the following disclaimers remain intact when
 * the source is distributed.  Object code and binary distributions may be made
 * as if the code were in the public domain.
 *
 * THIS CODE WAS NOT MADE IN ASSOCIATION WITH NINTENDO AND DOES NOT MAKE USE
 * OF ANY INTELLECTUAL PROPERTY CLAIMED BY NINTENDO.
 *
 * GAMEBOY ADVANCE IS A TRADEMARK OF NINTENDO.
 *
 * THIS CODE HAS BEEN PROVIDED "AS-IS" WITHOUT A WARRANTY OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO IMPLIED WARRANTIES OF
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  THE ENTIRE RISK AS TO THE
 * QUALITY OR PERFORMANCE OF THE CODE IS WITH YOU.
 *
 * IN NO EVENT, UNLESS AGREED TO IN WRITING, WILL ANY COPYRIGHT HOLDER, OR ANY
 * OTHER PARTY, BE HELD LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OR
 * INABILITY TO USE THIS CODE.
 *****************************************************************************/

#define __asm__
#include <rtems/asm.h>
#include <asm_macros.h>
#include <arm_mode_bits.h>
/* @cond  INCLUDE_ASM */

#ifndef NINTENDO_LOGO
#define NINTENDO_LOGO 1
#endif

#ifndef GBA_MULTIBOOT
#define GBA_MULTIBOOT 1
#endif

#ifndef GAME_TITLE
#define GAME_TITLE "RTEMS-RTOS  "
#endif

#ifdef GBA_MULTIBOOT
  #ifndef GAME_CODE
  #define GAME_CODE "MB  "
  #endif
  #ifndef COMPLEMENT_CHECK
  #define COMPLEMENT_CHECK 0xE2
  #endif
#else
  #ifndef GAME_CODE
  #define GAME_CODE "GBA "
  #endif
  #ifndef COMPLEMENT_CHECK
  #define COMPLEMENT_CHECK 0xC7
  #endif
#endif

#ifndef MAKER_CODE
#define MAKER_CODE "00"
#endif

/**
 *  RTEMS entry point
 *  function void _start(void)
 *
 */
/*****************************************************************************\
                           ROM Header
\*****************************************************************************/

.text
.align
.arm

/*---------------------------------------------------------------------------+
|  Nintendo Header:
|   A special header is required or the GBA will refuse to run your code.
|
|  File offsets from 0x0200000 or 0x08000000.
+----------------------------------------------------------------------------*/
    PUBLIC_ARM_FUNCTION(_start)
         b       SYM(_real_start)    /* 0x00 Entry Point                     */
    SYM(_gba_rom_header):
#if NINTENDO_LOGO                    /* 0x04 Nintendo Logo Character Data    */
#include        "logo.S"
#else
        .fill   156, 1, 0            /* 0x04 Nintendo Logo Character Data    */
#endif
        .ascii  GAME_TITLE           /* 0xA0 Game Title                      */
        .ascii  GAME_CODE            /* 0xAC Game Code                       */
        .ascii  MAKER_CODE           /* 0xB0 Maker Code                      */
        .byte   0x96                 /* 0xB2 Fixed Value                     */
        .byte   0                    /* 0xB3 Main Unit Code                  */
        .byte   0                    /* 0xB4 Device Type                     */
        .byte   0, 0, 0, 0, 0, 0, 0  /* 0xB5 Reserved (7 Bytes)              */
        .byte   0                    /* 0xBC Software Version No.            */
        .byte   COMPLEMENT_CHECK     /* 0xBD Complement Check                */
        .byte   0, 0                 /* 0xBE Reserved                        */
    .Lheader_end:


#if GBA_MULTIBOOT
/*---------------------------------------------------------------------------+
|  Multiboot Header:
|  The following header is required if the code is meant for Multiboot.
|
|  If the code has been downloaded through the serial port, then the GBA BIOS
|  will set offset 0xC0 depending on the boot method:
|  1 = JoyBus, 3 = Multiboot
|  It remains 0 for cartridges.
|
|  offset 0xC4 will be set to the GBA's assigned slave number 1-3.
|  This header also defines the symbols _boot_method and _slave_number for
|  easy reference to these values.  Some libraries may depend on them whether
|  or not the code is meant for Multiboot.
|
+----------------------------------------------------------------------------*/
    SYM(_gba_multiboot_start):
        b       SYM(_real_start)               /* 0xC0 Multiboot Entry Point */
    OBJECT(_boot_method)
        .byte   0                              /* 0xC4 Boot Method           */
    OBJECT(_slave_number)
        .byte   0                              /* 0xC5 Slave Number (1-3)    */
        .align
    STATIC_OBJECT(_gba_mb_reserved)
        .word   0, 0, 0, 0, 0, 0               /* 0xC8 Reserved (6 words)    */
    SYM(_gba_joybus_start):
        b       SYM(_real_start)               /* 0xE0 JoyBus Entry Point    */
    .Lmultiboot_header_end:
#endif

/*---------------------------------------------------------------------------+
|    Restore registers and stack from GBA bios IRQ frame and call ISR_Handler
+----------------------------------------------------------------------------*/
    EXTERN(_ISR_Handler)
    .align
    PUBLIC_ARM_FUNCTION(_gba_ISR_handler)
        ldmfd  r13!,{r0-r3,r12,r14}
        b      _ARMV4_Exception_interrupt
    LABEL_END(_gba_ISR_handler)


/*---------------------------------------------------------------------------+
|    Code to initialize the low-level BSP environment
+----------------------------------------------------------------------------*/
    SYM(_real_start):
    /* Initialize IRQ and USR Stack Pointers */
    SYM(_gba_init_stacks):
        mov     r0, #(Mode_IRQ | Int_Bits)       /* No interrupts            */
        msr     cpsr, r0                         /* switch to IRQ mode       */
        ldr     sp, =__sp_irq                    /* defined in linkcmds      */
        mov     r0, #(ModePriv | Int_Bits)       /* No interrupts            */
        msr     cpsr, r0                         /* switch to System Mode    */
        ldr     sp, =__sp_usr                    /* defined in linkcmds      */

    /* Switch to Thumb Mode */
    SYM(_gba_bx_thumb):
        adr     r0, .Lthumb + 1
        bx      r0
        .thumb
    .Lthumb:
    /* Reduce gameboy waitstates */
    SYM(_reduce_waitstates):
        ldr     r1, =0x4000204
        ldrh    r0, =0x4490
        strh    r0, [r1]


#if GBA_MULTIBOOT
/*---------------------------------------------------------------------------+
|  Load Multiboot Image from ROM into RAM:
|  Check to see if the image is meant for Multiboot or GamePak.  If it is for
|  Multiboot then check if it is currently running from EWRAM or from CARTROM.
|  If it is running from CARTROM, then it needs to be copied to EWRAM and
|  re-executed from the beginning.
|
|  The reason for all this is to allow a program to be used "as-is" with a
|  flash-cart, emulator, or MBV2-style Multiboot cable without rebuilding.
|
|  NOTE: Any branchs used above this code need to be relative.
+----------------------------------------------------------------------------*/
    STATIC_THUMB_FUNCTION(_gba_load_multiboot)
        ldr     r0, =_start            /* 8000000h=GamePak 2000000h=Multiboot*/
        ldr     r1, =__gba_rom_start   /* defined in linkcmds                */
        cmp     r0, r1
        beq     SYM(_no_load_multiboot)/* skip if GamePak                    */
        mov     r3, pc
        cmp     r1, r3                 /* check program counter              */
        bhi     SYM(_no_load_multiboot)/* skip if already running from EWRAM */
        sub     r3, r1, r0             /* diff between _start and CARTROM    */
        ldr     r2, =__load_stop_data  /* defined in linkcmds                */
        add     r2, r2, r3             /* adjust pointer into ROM            */
        bl      SYM(gba_move_memory)

        /* patch multiboot header */
        ldr     r0, =SYM(_boot_method)
        mov     r1, #3
        str     r1, [r0]

        /* remember that multiboot image came from GamePak */
        ldr     r0, =SYM(_gba_flash_loaded_multiboot)
        mov     r1, #0
        str     r1, [r0]

        ldr     r0, =SYM(_start)
        bx      r0                      /* restart                           */
    LABEL_END(_gba_load_multiboot)

        .align 4
    OBJECT(_gba_flash_loaded_multiboot)
        .word -1
    LABEL_END(_gba_flash_loaded_multiboot)
    SYM(_no_load_multiboot):
#endif

/* Initialize Standard Sections */
    STATIC_THUMB_FUNCTION(_gba_init_std_sections)
        /* Copy internal work ram (iwram section ROM to RAM)*/
        ldr     r0,=__iwram_start
        ldr     r1,=__load_start_iwram
        ldr     r2,=__load_stop_iwram
        bl      SYM(gba_move_memory)

        /* Copy external work ram (ewram section ROM to RAM) */
        ldr     r0,=__ewram_start
        ldr     r1,=__load_start_ewram
        ldr     r2,=__load_stop_ewram
        bl      SYM(gba_move_memory)

        /* load initial values of variables like 'int foo = 42' */
        ldr     r0, =__data_start      /* defined in linkcmds               */
        ldr     r1, =__load_start_data /* defined in linkcmds               */
        ldr     r2, =__load_stop_data  /* defined in linkcmds               */
        bl      SYM(gba_move_memory)

        /* zero the bss */
        ldr     r0, =__bss_start       /* defined in linkcmds               */
        ldr     r1, =__bss_end         /* defined in linkcmds               */
        bl      SYM(gba_zero_memory)
    LABEL_END(_gba_init_std_sections)

/* Initialize Interrupt Vector */
    STATIC_THUMB_FUNCTION(_gba_init_intr_vect)
        ldr     r1, =__irq_vector    /* defined in linkcmds                 */
        ldr     r0, =SYM(_gba_ISR_handler)
        str     r0, [r1]
    LABEL_END(_gba_init_intr_vect)


/* Enter the C code.  If it returns, then restart */
    STATIC_THUMB_FUNCTION(_gba_call_arm_boot_card)
        adr     r1, .Larm
        bx      r1
        .arm
    .Larm:
        ldr     r1, =boot_card
        mov     r0, #0
        bl      SYM(_gba_call_via_r1)

        ldr     r0, =SYM(_gba_reset)
    SYM(_gba_call_via_r1):
        bx      r1

/* GBA Reset  */
    PUBLIC_ARM_FUNCTION(_gba_reset)
        adr     r0, .Lthumb2 + 1
        bx      r0
        .thumb
    .Lthumb2:
        /* disable interrupts */
        ldr     r0, =0x04000208
        mov     r1, #0
        strb    r1, [r0]

        /* reset stack, default free area */
        ldr     r0, =0x03007F00
        mov     sp, r0

#if GBA_MULTIBOOT
        ldr     r0, =SYM(_gba_flash_loaded_multiboot)
        ldr     r0, [r0]
        cmp     r0, #0
        beq     SYM(_reset)
#endif

        ldr     r0, =_start            /* defined in linkcmds               */
        ldr     r1, =__gba_rom_start   /* defined in linkcmds               */
        sub     r0, r0, r1
        lsr     r0, r0, #24

   SYM(_reset):
        /* soft reset (swi 0) parameter: where is _start */
        ldr     r1, =0x03007FFA
        strb    r0, [r1]
        mov     r0, #0xFE              /* clear all but EWRAM               */
        swi     1
        swi     0
    LABEL_END(_gba_reset)


/*---------------------------------------------------------------------------+
|   Library Functions
+----------------------------------------------------------------------------*/

/* gba_zero_memory */
    PUBLIC_THUMB_FUNCTION(gba_zero_memory)
        mov     r2, #0
        nop
    LABEL_END(gba_zero_memory)

/* gba_set_memory */
    PUBLIC_THUMB_FUNCTION(gba_set_memory)
        cmp     r0, r1
        bcs     .Lset_memory_return

    .Lset_memory_loop:
        stmia   r0!, {r2}
        cmp     r0, r1
        bcc     .Lset_memory_loop

    .Lset_memory_return:
        bx      lr
    LABEL_END(gba_set_memory)

/* gba_move_memory */
    .align
    PUBLIC_THUMB_FUNCTION(gba_move_memory)
        cmp     r0, r1
        bcc     .Lforward_move  /* if dst < src then forward copy */
        bhi     .Lreverse_move  /* if dst > src then reverse copy */
        bx      lr              /* else dst == src, nothing to do */

    .Lforward_move:
        cmp     r1, r2
        bcs     .Lmove_memory_return

    .Lforward_move_loop:
        ldmia   r1!, {r3}
        stmia   r0!, {r3}
        cmp     r1, r2
        bcc     .Lforward_move_loop
        bx      lr

    .Lreverse_move:
        cmp     r2, r1
        bls     .Lmove_memory_return
        sub     r3, r2, r1
        add     r0, r0, r3

    .Lreverse_move_loop:
        sub     r2, r2, #4
        ldr     r3, [r2]
        sub     r0, r0, #4
        str     r3, [r0]
        cmp     r2, r1
        bhi     .Lreverse_move_loop

    .Lmove_memory_return:
        bx      lr
    LABEL_END(gba_move_memory)


/* @todo FIXME: Remove unused handler needed by ../score/cpu_asm.S
 *****************************************************************************/
        .arm
        .global SWI_Handler
SWI_Handler:
        mov pc, lr
/* @endcond     */