diff options
Diffstat (limited to 'src/gba/gba.h')
-rw-r--r-- | src/gba/gba.h | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/src/gba/gba.h b/src/gba/gba.h new file mode 100644 index 0000000..56c4876 --- /dev/null +++ b/src/gba/gba.h | |||
@@ -0,0 +1,667 @@ | |||
1 | #ifndef GBA_H | ||
2 | #define GBA_H | ||
3 | |||
4 | #include "shorthand.h" | ||
5 | |||
6 | #define CPU_FREQUENCY (2 << 23) | ||
7 | |||
8 | // | ||
9 | // Memory sections. | ||
10 | // | ||
11 | |||
12 | // Defines for the different memory sections in the GBA. | ||
13 | #define MEM_SROM 0x00000000 | ||
14 | #define MEM_EW 0x02000000 | ||
15 | #define MEM_IW 0x03000000 | ||
16 | #define MEM_IO 0x04000000 | ||
17 | #define MEM_PAL 0x05000000 | ||
18 | #define MEM_VRAM 0x06000000 | ||
19 | #define MEM_OAM 0x07000000 | ||
20 | #define MEM_PAK 0x08000000 | ||
21 | #define MEM_CART 0x0E000000 | ||
22 | |||
23 | // | ||
24 | // Display modes. | ||
25 | // | ||
26 | |||
27 | // Display registers. | ||
28 | #define DISP_CTRL *((vu32*)(MEM_IO + 0x0000)) | ||
29 | #define DISP_STATUS *((vu16*)(MEM_IO + 0x0004)) | ||
30 | #define DISP_VCOUNT *((vu16*)(MEM_IO + 0x0006)) | ||
31 | |||
32 | // The first three bits in the DISP_CTRL are used to control the video mode. | ||
33 | #define DISP_MODE_0 0x0000 | ||
34 | #define DISP_MODE_1 0x0001 | ||
35 | #define DISP_MODE_2 0x0002 | ||
36 | #define DISP_MODE_3 0x0003 | ||
37 | #define DISP_MODE_4 0x0004 | ||
38 | #define DISP_MODE_5 0x0005 | ||
39 | #define DISP_GB (1 << 3) | ||
40 | #define DISP_PAGE (1 << 4) | ||
41 | #define DISP_OAM_HBLANK (1 << 5) | ||
42 | #define DISP_OBJ_1D (1 << 6) | ||
43 | #define DISP_BLANK (1 << 7) | ||
44 | #define DISP_BG_0 (1 << 8) | ||
45 | #define DISP_BG_1 (1 << 9) | ||
46 | #define DISP_BG_2 (1 << 10) | ||
47 | #define DISP_BG_3 (1 << 11) | ||
48 | #define DISP_OBJ (1 << 12) | ||
49 | #define DISP_ENABLE_SPRITES DISP_OBJ | DISP_OBJ_1D | ||
50 | |||
51 | // These bits are used to control the DISP_STATUS register. | ||
52 | #define DISP_VBLANK_STATUS (1 << 0x0) | ||
53 | #define DISP_HBLANK_STATUS (1 << 0x1) | ||
54 | #define DISP_VCOUNT_STATUS (1 << 0x2) | ||
55 | #define DISP_VBLANK_IRQ (1 << 0x3) | ||
56 | #define DISP_HBLANK_IRQ (1 << 0x4) | ||
57 | #define DISP_VCOUNT_IRQ (1 << 0x5) | ||
58 | #define DISP_VCOUNT_TRIGGER(N) ((N) << 0x8) | ||
59 | |||
60 | // Registers to control of BG layers. | ||
61 | #define BG_CTRL(N) *((vu16*)(0x04000008 + 0x0002 * (N))) | ||
62 | |||
63 | // Bits to control the background. | ||
64 | #define BG_PRIORITY(N) ((N) & 0x3) | ||
65 | #define BG_CHARBLOCK(N) ((N) << 2) | ||
66 | #define BG_MOSAIC (1 << 6) | ||
67 | #define BG_HIGH_COLOR (1 << 7) | ||
68 | #define BG_SCREENBLOCK(N) ((N) << 8) | ||
69 | #define BG_AFFINE (1 << 0xD) | ||
70 | #define BG_SIZE(N) ((N) << 0xE) | ||
71 | |||
72 | // BG registers for horizontal displacement. | ||
73 | #define BG_H_SCROLL_0 *((vu16*)(0x04000010 + 0x0004 * 0)) | ||
74 | #define BG_H_SCROLL_1 *((vu16*)(0x04000010 + 0x0004 * 1)) | ||
75 | #define BG_H_SCROLL_2 *((vu16*)(0x04000010 + 0x0004 * 2)) | ||
76 | #define BG_H_SCROLL_3 *((vu16*)(0x04000010 + 0x0004 * 3)) | ||
77 | |||
78 | // BG registers for vertical displacement. | ||
79 | #define BG_V_SCROLL_0 *((vu16*)(0x04000012 + 0x0004 * 0)) | ||
80 | #define BG_V_SCROLL_1 *((vu16*)(0x04000012 + 0x0004 * 1)) | ||
81 | #define BG_V_SCROLL_2 *((vu16*)(0x04000012 + 0x0004 * 2)) | ||
82 | #define BG_V_SCROLL_3 *((vu16*)(0x04000012 + 0x0004 * 3)) | ||
83 | |||
84 | // Screen settings. | ||
85 | #define SCREEN_WIDTH 240 | ||
86 | #define SCREEN_HEIGHT 160 | ||
87 | |||
88 | // | ||
89 | // Colors. | ||
90 | // | ||
91 | |||
92 | // The GBA in mode 3 expects rbg15 colors in the VRAM, where each component | ||
93 | // (RGB) have a 0--31 range. For example, pure red would be rgb15(31, 0, 0). | ||
94 | typedef u16 Color; | ||
95 | |||
96 | // A palette is composed of 16 colors, with color at index 0 being transparent | ||
97 | // for sprites. | ||
98 | typedef Color Palette[16]; | ||
99 | |||
100 | // Inline function to calculate the 15 bit color value. | ||
101 | #define RGB15(R,G,B) (u16)(((B) << 10) | ((G) << 5) | (R)); | ||
102 | |||
103 | // Some nice default colors. | ||
104 | #define COLOR_RED RGB15(31, 0,12) | ||
105 | #define COLOR_BLUE RGB15(2, 15,30) | ||
106 | #define COLOR_CYAN RGB15(0, 30,30) | ||
107 | #define COLOR_GREY RGB15(12,12,12) | ||
108 | #define COLOR_BLACK RGB15(0, 0, 0) | ||
109 | #define COLOR_WHITE RGB15(28,28,28) | ||
110 | |||
111 | // | ||
112 | // Tile memory access. | ||
113 | // | ||
114 | |||
115 | // NOTE: Only defining 4bpp tiles for now. | ||
116 | // TODO: typedef u32 Tile[8]; | ||
117 | typedef struct Tile { | ||
118 | u32 row[8]; | ||
119 | } Tile; | ||
120 | |||
121 | // Screenblocks and charblocks (tile blocks). | ||
122 | typedef Tile TileBlock[512]; | ||
123 | #define TILE_MEM ((TileBlock*) MEM_VRAM) | ||
124 | typedef u16 ScreenBlock[1024]; | ||
125 | #define SCREENBLOCK_MEM ((ScreenBlock*)MEM_VRAM) | ||
126 | |||
127 | // Screenblock entry bits. | ||
128 | #define SCREENBLOCK_ENTRY_H_FLIP (1 << 0xA) | ||
129 | #define SCREENBLOCK_ENTRY_V_FLIP (1 << 0xB) | ||
130 | #define SCREENBLOCK_ENTRY_PAL(N) ((N) << 0xC) | ||
131 | |||
132 | inline size_t | ||
133 | se_index(size_t tile_x, size_t tile_y, size_t map_width) { | ||
134 | size_t sbb = ((tile_x >> 5) + (tile_y >> 5) * (map_width >> 5)); | ||
135 | return sbb * 1024 + ((tile_x & 31) + (tile_y & 31) * 32); | ||
136 | } | ||
137 | |||
138 | // We can treat the screen as a HxW matrix. With the following macro we can | ||
139 | // write a pixel to the screen at the (x, y) position using: | ||
140 | // | ||
141 | // FRAMEBUFFER[y][x] = color; | ||
142 | // | ||
143 | typedef Color Scanline[SCREEN_WIDTH]; | ||
144 | #define FRAMEBUFFER ((Scanline*) MEM_VRAM) | ||
145 | #define SCREEN_BUFFER ((u16*) MEM_VRAM) | ||
146 | #define PAL_BUFFER_BG ((u16*) MEM_PAL) | ||
147 | #define PAL_BUFFER_SPRITES ((u16*)(MEM_PAL + 0x200)) | ||
148 | #define PAL_BANK_BG ((Palette*) MEM_PAL) | ||
149 | #define PAL_BANK_SPRITES ((Palette*)(MEM_PAL + 0x200)) | ||
150 | |||
151 | // | ||
152 | // Sprites. | ||
153 | // | ||
154 | |||
155 | // Using macros instead of aligned structs for setting up OBJ attributes and | ||
156 | // affine parameters. | ||
157 | // TODO: Benchmark if this would be slower or the same that TONC's | ||
158 | // implementation. | ||
159 | // TODO: Cleanup OBJ/OAM memory copying and access. | ||
160 | #define OBJ_ATTR_0(N) *((vu16*)(MEM_OAM + 0 + 8 * (N))) | ||
161 | #define OBJ_ATTR_1(N) *((vu16*)(MEM_OAM + 2 + 8 * (N))) | ||
162 | #define OBJ_ATTR_2(N) *((vu16*)(MEM_OAM + 4 + 8 * (N))) | ||
163 | #define OBJ_AFFINE_PA(N) *((vs16*)(MEM_OAM + 6 + 8 * 0 + 8 * 4 * (N))) | ||
164 | #define OBJ_AFFINE_PB(N) *((vs16*)(MEM_OAM + 6 + 8 * 1 + 8 * 4 * (N))) | ||
165 | #define OBJ_AFFINE_PC(N) *((vs16*)(MEM_OAM + 6 + 8 * 2 + 8 * 4 * (N))) | ||
166 | #define OBJ_AFFINE_PD(N) *((vs16*)(MEM_OAM + 6 + 8 * 3 + 8 * 4 * (N))) | ||
167 | |||
168 | // OBJ_ATTR_0 parameters | ||
169 | #define OBJ_Y_COORD(N) ((N) & 0xFF) | ||
170 | #define OBJ_NORMAL (0x00 << 0x8) | ||
171 | #define OBJ_AFFINE (0x01 << 0x8) | ||
172 | #define OBJ_HIDDEN (0x02 << 0x8) | ||
173 | #define OBJ_AFFINE_2X (0x03 << 0x8) | ||
174 | #define OBJ_ALPHA_BLEND (0x01 << 0xA) | ||
175 | #define OBJ_WINDOW (0x02 << 0xA) | ||
176 | #define OBJ_SHAPE_SQUARE (0x00 << 0xE) | ||
177 | #define OBJ_SHAPE_WIDE (0x01 << 0xE) | ||
178 | #define OBJ_SHAPE_TALL (0x02 << 0xE) | ||
179 | |||
180 | // OBJ_ATTR_1 parameters | ||
181 | #define OBJ_X_COORD(N) ((N) & 0x1FF) | ||
182 | #define OBJ_AFFINE_IDX(N) ((N) << 0x9) | ||
183 | #define OBJ_H_FLIP (0x01 << 0xC) | ||
184 | #define OBJ_V_FLIP (0x01 << 0xD) | ||
185 | #define OBJ_SIZE_SMALL (0x00 << 0xE) | ||
186 | #define OBJ_SIZE_MID (0x01 << 0xE) | ||
187 | #define OBJ_SIZE_BIG (0x02 << 0xE) | ||
188 | #define OBJ_SIZE_HUGE (0x03 << 0xE) | ||
189 | |||
190 | // OBJ_ATTR_2 parameters | ||
191 | #define OBJ_TILE_INDEX(N) ((N) & 0x3FF) | ||
192 | #define OBJ_PRIORITY(N) ((N) << 0xA) | ||
193 | #define OBJ_PAL_BANK(N) ((N) << 0xC) | ||
194 | |||
195 | // | ||
196 | // Mode 4 page flipping | ||
197 | // | ||
198 | |||
199 | static inline | ||
200 | void | ||
201 | flip_page(vu16 *backbuffer) { | ||
202 | backbuffer = (u16*)((u32)backbuffer ^ 0x0A000); | ||
203 | DISP_CTRL ^= DISP_PAGE; | ||
204 | } | ||
205 | |||
206 | #define SCREEN_PAGE_1 ((vu16*) MEM_VRAM) | ||
207 | #define SCREEN_PAGE_2 ((vu16*) (MEM_VRAM + 0xa000)) | ||
208 | |||
209 | // | ||
210 | // Profiling. | ||
211 | // | ||
212 | |||
213 | #define TIMER_DATA_0 *((vu16*) (0x04000100 + 0x04 * 0)) | ||
214 | #define TIMER_DATA_1 *((vu16*) (0x04000100 + 0x04 * 1)) | ||
215 | #define TIMER_DATA_2 *((vu16*) (0x04000100 + 0x04 * 2)) | ||
216 | #define TIMER_DATA_3 *((vu16*) (0x04000100 + 0x04 * 3)) | ||
217 | #define TIMER_CTRL_0 *((vu16*) (0x04000102 + 0x04 * 0)) | ||
218 | #define TIMER_CTRL_1 *((vu16*) (0x04000102 + 0x04 * 1)) | ||
219 | #define TIMER_CTRL_2 *((vu16*) (0x04000102 + 0x04 * 2)) | ||
220 | #define TIMER_CTRL_3 *((vu16*) (0x04000102 + 0x04 * 3)) | ||
221 | |||
222 | // Timer control bits. | ||
223 | #define TIMER_CTRL_FREQ_0 0 | ||
224 | #define TIMER_CTRL_FREQ_1 1 | ||
225 | #define TIMER_CTRL_FREQ_2 2 | ||
226 | #define TIMER_CTRL_FREQ_3 3 | ||
227 | #define TIMER_CTRL_CASCADE (1 << 2) | ||
228 | #define TIMER_CTRL_IRQ (1 << 6) | ||
229 | #define TIMER_CTRL_ENABLE (1 << 7) | ||
230 | #define TIMER_CTRL_DISABLE (0 << 7) | ||
231 | |||
232 | // We use timers 2 and 3 to count the number of cycles since the profile_start | ||
233 | // functions is called. Don't use if the code we are trying to profile make use | ||
234 | // of these timers. | ||
235 | static inline | ||
236 | void | ||
237 | profile_start(void) { | ||
238 | TIMER_DATA_2 = 0; | ||
239 | TIMER_DATA_3 = 0; | ||
240 | TIMER_CTRL_2 = 0; | ||
241 | TIMER_CTRL_3 = 0; | ||
242 | TIMER_CTRL_3 = TIMER_CTRL_ENABLE | TIMER_CTRL_CASCADE; | ||
243 | TIMER_CTRL_2 = TIMER_CTRL_ENABLE; | ||
244 | } | ||
245 | |||
246 | static inline | ||
247 | u32 | ||
248 | profile_stop(void) { | ||
249 | TIMER_CTRL_2 = 0; | ||
250 | return (TIMER_DATA_3 << 16) | TIMER_DATA_2; | ||
251 | } | ||
252 | |||
253 | static inline | ||
254 | u32 | ||
255 | profile_measure(void) { | ||
256 | return (TIMER_DATA_3 << 16) | TIMER_DATA_2; | ||
257 | } | ||
258 | |||
259 | // | ||
260 | // Input handling. | ||
261 | // | ||
262 | |||
263 | // Memory address for key input and control register | ||
264 | #define KEY_INPUTS *((vu16*) 0x04000130) | ||
265 | #define KEY_CTRL *((vu16*) 0x04000132) | ||
266 | |||
267 | // Key control register bits. | ||
268 | #define KEY_IRQ_KEY(N) (N) | ||
269 | #define KEY_IRQ (1 << 0xE) | ||
270 | #define KEY_IRQ_IF_SET (1 << 0xF) | ||
271 | |||
272 | // Alias for key pressing bits. | ||
273 | #define KEY_A (1 << 0) | ||
274 | #define KEY_B (1 << 1) | ||
275 | #define KEY_SELECT (1 << 2) | ||
276 | #define KEY_START (1 << 3) | ||
277 | #define KEY_RIGHT (1 << 4) | ||
278 | #define KEY_LEFT (1 << 5) | ||
279 | #define KEY_UP (1 << 6) | ||
280 | #define KEY_DOWN (1 << 7) | ||
281 | #define KEY_R (1 << 8) | ||
282 | #define KEY_L (1 << 9) | ||
283 | |||
284 | #define KEY_MASK 0x03FF | ||
285 | |||
286 | // Saving the previous and current key states as globals for now. | ||
287 | static u16 key_curr = 0; | ||
288 | static u16 key_prev = 0; | ||
289 | |||
290 | static inline | ||
291 | void | ||
292 | poll_keys(void) { | ||
293 | key_prev = key_curr; | ||
294 | key_curr = ~KEY_INPUTS & KEY_MASK; | ||
295 | } | ||
296 | |||
297 | // Returns true if the given key has been pressed at time of calling and was not | ||
298 | // pressed since the previous call. For example, if a key is being held, this | ||
299 | // function will return `true` only on the frame where the key initially | ||
300 | // activated. | ||
301 | static inline | ||
302 | u32 | ||
303 | key_tap(u32 key) { | ||
304 | return (key_curr & key) & ~(key_prev & key); | ||
305 | } | ||
306 | |||
307 | // Check if a given key is currently pressed. | ||
308 | static inline | ||
309 | u32 | ||
310 | key_pressed(u32 key) { | ||
311 | return (key_curr & key); | ||
312 | } | ||
313 | |||
314 | // Check if a given key was just released. | ||
315 | static inline | ||
316 | u32 | ||
317 | key_released(u32 key) { | ||
318 | return ~(key_curr & key) & (key_prev & key); | ||
319 | } | ||
320 | |||
321 | // Check if the given key is pressed and has been since at least one frame. | ||
322 | static inline | ||
323 | u32 | ||
324 | key_hold(u32 key) { | ||
325 | return key_curr & key_prev & key; | ||
326 | } | ||
327 | |||
328 | // Check if the given key/button is currently pressed. | ||
329 | #define KEY_PRESSED(key) (~(KEY_INPUTS) & key) | ||
330 | |||
331 | // Back/unpack bits. | ||
332 | static inline | ||
333 | u32 | ||
334 | unpack_1bb(u8 hex) { | ||
335 | const u32 conversion_u32[16] = { | ||
336 | 0x00000000, 0x00000001, 0x00000010, 0x00000011, | ||
337 | 0x00000100, 0x00000101, 0x00000110, 0x00000111, | ||
338 | 0x00001000, 0x00001001, 0x00001010, 0x00001011, | ||
339 | 0x00001100, 0x00001101, 0x00001110, 0x00001111, | ||
340 | }; | ||
341 | u8 low = hex & 0xF; | ||
342 | u8 high = (hex >> 4) & 0xF; | ||
343 | return (conversion_u32[high] << 16) | conversion_u32[low]; | ||
344 | } | ||
345 | |||
346 | // Unpack N tiles packed at 1bpp. | ||
347 | static inline | ||
348 | void | ||
349 | unpack_tiles(u32 *src, u32 *dst, size_t n_tiles) { | ||
350 | u32 *target_src = src + n_tiles * 2; | ||
351 | while (src != target_src) { | ||
352 | *dst++ = unpack_1bb((*src >> 24) & 0xFF); | ||
353 | *dst++ = unpack_1bb((*src >> 16) & 0xFF); | ||
354 | *dst++ = unpack_1bb((*src >> 8) & 0xFF); | ||
355 | *dst++ = unpack_1bb(*src & 0xFF); | ||
356 | src++; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | // | ||
361 | // Direct Memory Access (DMA) | ||
362 | // | ||
363 | |||
364 | |||
365 | // Source, destination, and control registers. | ||
366 | #define DMA_SRC(N) *((vu32*) 0x040000B0 + (N) * 12) | ||
367 | #define DMA_DST(N) *((vu32*) 0x040000B4 + (N) * 12) | ||
368 | #define DMA_CTRL(N) *((vu32*) 0x040000B8 + (N) * 12) | ||
369 | |||
370 | // DMA control bits. | ||
371 | #define DMA_DST_INC (0 << 0x15) | ||
372 | #define DMA_DST_DEC (1 << 0x15) | ||
373 | #define DMA_DST_FIXED (2 << 0x15) | ||
374 | #define DMA_DST_RELOAD (3 << 0x15) | ||
375 | #define DMA_SRC_INC (0 << 0x17) | ||
376 | #define DMA_SRC_DEC (1 << 0x17) | ||
377 | #define DMA_SRC_FIXED (2 << 0x17) | ||
378 | #define DMA_REPEAT (1 << 0x19) | ||
379 | #define DMA_CHUNK_16 (0 << 0x1A) | ||
380 | #define DMA_CHUNK_32 (1 << 0x1A) | ||
381 | #define DMA_NOW (0 << 0x1C) | ||
382 | #define DMA_VBLANK (1 << 0x1C) | ||
383 | #define DMA_HBLANK (2 << 0x1C) | ||
384 | #define DMA_REFRESH (3 << 0x1C) | ||
385 | #define DMA_IRQ (1 << 0x1E) | ||
386 | #define DMA_ENABLE (1 << 0x1F) | ||
387 | |||
388 | // Custom struct for cleaner DMA transfer functions. | ||
389 | typedef struct DmaStr { | ||
390 | const void *src; | ||
391 | void *dst; | ||
392 | u32 ctrl; | ||
393 | } DmaStr; | ||
394 | |||
395 | #define DMA_TRANSFER ((volatile DmaStr*) 0x040000B0) | ||
396 | |||
397 | // Transfer `count` number of chunks from src to dst using a DMA channel. Note | ||
398 | // that chunks are not bytes, but instead configured based on bits set by | ||
399 | // DMA_CTRL. | ||
400 | inline | ||
401 | void | ||
402 | dma_transfer_copy(void *dst, const void *src, u32 count, int channel, u32 options) { | ||
403 | DMA_TRANSFER[channel].ctrl = 0; | ||
404 | DMA_TRANSFER[channel].src = src; | ||
405 | DMA_TRANSFER[channel].dst = dst; | ||
406 | DMA_TRANSFER[channel].ctrl = count | options; | ||
407 | } | ||
408 | |||
409 | inline | ||
410 | void | ||
411 | dma_transfer_fill(void *dst, volatile u32 src, u32 count, int channel, u32 options) { | ||
412 | DMA_TRANSFER[channel].ctrl = 0; | ||
413 | DMA_TRANSFER[channel].src = (const void *)&src; | ||
414 | DMA_TRANSFER[channel].dst = dst; | ||
415 | DMA_TRANSFER[channel].ctrl = count | options | DMA_SRC_FIXED; | ||
416 | } | ||
417 | |||
418 | // Copy N number of bytes using a DMA channel. | ||
419 | inline | ||
420 | void | ||
421 | dma_copy(void *dst, const void *src, u32 size, int channel) { | ||
422 | dma_transfer_copy(dst, src, size / 4, channel, DMA_CHUNK_32 | DMA_ENABLE); | ||
423 | } | ||
424 | |||
425 | // Fill the dst location with the word set at src. | ||
426 | inline | ||
427 | void | ||
428 | dma_fill(void *dst, vu32 src, u32 size, int channel) { | ||
429 | dma_transfer_fill(dst, src, size / 4, channel, DMA_CHUNK_32 | DMA_ENABLE); | ||
430 | } | ||
431 | |||
432 | // | ||
433 | // Interrupts. | ||
434 | // | ||
435 | |||
436 | #define IRQ_ENABLE *((vu16*) 0x04000200) | ||
437 | #define IRQ_ACK *((vu16*) 0x04000202) | ||
438 | #define IRQ_CTRL *((vu16*) 0x04000208) | ||
439 | #define IRQ_ACK_BIOS *((vu16*) 0x03007FF8) | ||
440 | |||
441 | typedef enum { | ||
442 | IRQ_VBLANK, | ||
443 | IRQ_HBLANK, | ||
444 | IRQ_VCOUNT, | ||
445 | IRQ_TIMER_0, | ||
446 | IRQ_TIMER_1, | ||
447 | IRQ_TIMER_2, | ||
448 | IRQ_TIMER_3, | ||
449 | IRQ_SERIAL, | ||
450 | IRQ_DMA_0, | ||
451 | IRQ_DMA_1, | ||
452 | IRQ_DMA_2, | ||
453 | IRQ_DMA_3, | ||
454 | IRQ_KEYPAD, | ||
455 | IRQ_GAMEPAK, | ||
456 | } IrqIndex; | ||
457 | |||
458 | typedef void (*IrsFunc)(void); | ||
459 | |||
460 | // Stub function pointer needed for when we want to enable interrupts that don't | ||
461 | // require a custom function, such as for the BIOS VSync. | ||
462 | void irs_stub(void); | ||
463 | |||
464 | // Set and enable a given function in the interrupt table. If func is NULL, the | ||
465 | // interrupt will be disabled instead. | ||
466 | void irs_set(IrqIndex idx, IrsFunc func); | ||
467 | |||
468 | // Initialize the function pointer for the main IRS routine written in ARM | ||
469 | // assembly and enable interrupts. | ||
470 | void irq_init(void); | ||
471 | |||
472 | // | ||
473 | // BIOS function declarations. | ||
474 | // | ||
475 | |||
476 | // These functions declarations can be used to call the BIOS functions from the | ||
477 | // asm code. | ||
478 | int bios_vblank_wait(); | ||
479 | int bios_div(int num, int denom); | ||
480 | |||
481 | // | ||
482 | // Sound. | ||
483 | // | ||
484 | |||
485 | // Sound registers. | ||
486 | #define SOUND_SQUARE1_SWEEP *((vu16*)(MEM_IO + 0x60)) | ||
487 | #define SOUND_SQUARE1_CTRL *((vu16*)(MEM_IO + 0x62)) | ||
488 | #define SOUND_SQUARE1_FREQ *((vu16*)(MEM_IO + 0x64)) | ||
489 | #define SOUND_SQUARE2_CTRL *((vu16*)(MEM_IO + 0x68)) | ||
490 | #define SOUND_SQUARE2_FREQ *((vu16*)(MEM_IO + 0x6C)) | ||
491 | #define SOUND_WAVE_MODE *((vu16*)(MEM_IO + 0x70)) | ||
492 | #define SOUND_WAVE_CTRL *((vu16*)(MEM_IO + 0x72)) | ||
493 | #define SOUND_WAVE_FREQ *((vu16*)(MEM_IO + 0x74)) | ||
494 | #define SOUND_NOISE_CTRL *((vu16*)(MEM_IO + 0x78)) | ||
495 | #define SOUND_NOISE_FREQ *((vu16*)(MEM_IO + 0x7C)) | ||
496 | #define SOUND_DMG_MASTER *((vu16*)(MEM_IO + 0x80)) | ||
497 | #define SOUND_DSOUND_MASTER *((vu16*)(MEM_IO + 0x82)) | ||
498 | #define SOUND_STATUS *((vu16*)(MEM_IO + 0x84)) | ||
499 | #define SOUND_BIAS *((vu16*)(MEM_IO + 0x88)) | ||
500 | |||
501 | // Sound DMG master bits. | ||
502 | #define SOUND_VOLUME_LEFT(N) (N) | ||
503 | #define SOUND_VOLUME_RIGHT(N) ((N) << 4) | ||
504 | #define SOUND_ENABLE_SQUARE1_LEFT (1 << 0x8) | ||
505 | #define SOUND_ENABLE_SQUARE2_LEFT (1 << 0x9) | ||
506 | #define SOUND_ENABLE_WAVE_LEFT (1 << 0xA) | ||
507 | #define SOUND_ENABLE_NOISE_LEFT (1 << 0xB) | ||
508 | #define SOUND_ENABLE_SQUARE1_RIGHT (1 << 0xC) | ||
509 | #define SOUND_ENABLE_SQUARE2_RIGHT (1 << 0xD) | ||
510 | #define SOUND_ENABLE_WAVE_RIGHT (1 << 0xE) | ||
511 | #define SOUND_ENABLE_NOISE_RIGHT (1 << 0xF) | ||
512 | |||
513 | typedef enum { | ||
514 | SOUND_DSOUND = (0x0 << 0), | ||
515 | SOUND_SQUARE1 = (0x1 << 0), | ||
516 | SOUND_SQUARE2 = (0x1 << 1), | ||
517 | SOUND_WAVE = (0x1 << 2), | ||
518 | SOUND_NOISE = (0x1 << 3), | ||
519 | } SoundChannel; | ||
520 | |||
521 | inline u16 | ||
522 | sound_volume(SoundChannel channels, u8 volume) { | ||
523 | volume = volume & 0x7; | ||
524 | channels = channels & 0xF; | ||
525 | return volume | (volume << 0x4) | (channels << 0x8) | (channels << 0xC); | ||
526 | } | ||
527 | |||
528 | // Sound Direct Sound master bits. | ||
529 | #define SOUND_DMG25 0x0 | ||
530 | #define SOUND_DMG50 0x1 | ||
531 | #define SOUND_DMG100 0x2 | ||
532 | #define SOUND_DSOUND_RATIO_A (1 << 0x2) | ||
533 | #define SOUND_DSOUND_RATIO_B (1 << 0x3) | ||
534 | #define SOUND_DSOUND_LEFT_A (1 << 0x8) | ||
535 | #define SOUND_DSOUND_RIGHT_A (1 << 0x9) | ||
536 | #define SOUND_DSOUND_TIMER_A (1 << 0xA) | ||
537 | #define SOUND_DSOUND_RESET_A (1 << 0xB) | ||
538 | #define SOUND_DSOUND_LEFT_B (1 << 0xC) | ||
539 | #define SOUND_DSOUND_RIGHT_B (1 << 0xD) | ||
540 | #define SOUND_DSOUND_TIMER_B (1 << 0xE) | ||
541 | #define SOUND_DSOUND_RESET_B (1 << 0xF) | ||
542 | |||
543 | // Direct sound FIFO queues. | ||
544 | #define SOUND_FIFO_A ((u16*)(MEM_IO + 0xA0)) | ||
545 | #define SOUND_FIFO_B ((u16*)(MEM_IO + 0xA4)) | ||
546 | |||
547 | // Sound status bits. | ||
548 | #define SOUND_ENABLE (1 << 0x7) | ||
549 | |||
550 | // DMG square control bits. | ||
551 | #define SOUND_SQUARE_LEN(N) (N) | ||
552 | #define SOUND_SQUARE_DUTY(N) ((N) << 0x6) | ||
553 | #define SOUND_SQUARE_ENV_TIME(N) ((N) << 0x8) | ||
554 | #define SOUND_SQUARE_ENV_DIR(N) ((N) << 0xB) | ||
555 | #define SOUND_SQUARE_ENV_VOL(N) ((N) << 0xC) | ||
556 | |||
557 | // DMG square 1 sweep control bits. | ||
558 | #define SOUND_SWEEP_NUMBER(N) (N) | ||
559 | #define SOUND_SWEEP_DIR(N) ((N) << 0x3) | ||
560 | #define SOUND_SWEEP_TIME(N) ((N) << 0x4) | ||
561 | |||
562 | // DMG frequency bits (Square/Wave). | ||
563 | #define SOUND_FREQ_TIMED (1 << 0xE) | ||
564 | #define SOUND_FREQ_RESET (1 << 0xF) | ||
565 | |||
566 | // DMG wave ram. | ||
567 | #define SOUND_WAVE_RAM_0 *((vu32*)(MEM_IO + 0x90)) | ||
568 | #define SOUND_WAVE_RAM_1 *((vu32*)(MEM_IO + 0x94)) | ||
569 | #define SOUND_WAVE_RAM_2 *((vu32*)(MEM_IO + 0x98)) | ||
570 | #define SOUND_WAVE_RAM_3 *((vu32*)(MEM_IO + 0x9C)) | ||
571 | |||
572 | // DMG wave control bits. | ||
573 | #define SOUND_WAVE_LENGTH(N) (N) | ||
574 | #define SOUND_WAVE_MUTE 0x0 | ||
575 | #define SOUND_WAVE_VOL_100 (0x1 << 0xD) | ||
576 | #define SOUND_WAVE_VOL_75 (0x4 << 0xD) | ||
577 | #define SOUND_WAVE_VOL_50 (0x2 << 0xD) | ||
578 | #define SOUND_WAVE_VOL_25 (0x3 << 0xD) | ||
579 | |||
580 | // DMG wave mode bits. | ||
581 | #define SOUND_WAVE_BANK_MODE(N) ((N) << 0x5) | ||
582 | #define SOUND_WAVE_BANK_SELECT(N) ((N) << 0x6) | ||
583 | #define SOUND_WAVE_ENABLE (1 << 0x7) | ||
584 | |||
585 | typedef u8 WaveBank[32]; | ||
586 | |||
587 | #define SOUND_WAVE_RAM ((WaveBank*)(MEM_IO + 0x90)) | ||
588 | |||
589 | typedef enum { | ||
590 | NOTE_C_2 , NOTE_C_SHARP_2 , NOTE_D_2 , NOTE_D_SHARP_2 , | ||
591 | NOTE_E_2 , NOTE_F_2 , NOTE_F_SHARP_2 , NOTE_G_2 , | ||
592 | NOTE_G_SHARP_2 , NOTE_A_2 , NOTE_A_SHARP_2 , NOTE_B_2 , | ||
593 | NOTE_C_3 , NOTE_C_SHARP_3 , NOTE_D_3 , NOTE_D_SHARP_3 , | ||
594 | NOTE_E_3 , NOTE_F_3 , NOTE_F_SHARP_3 , NOTE_G_3 , | ||
595 | NOTE_G_SHARP_3 , NOTE_A_3 , NOTE_A_SHARP_3 , NOTE_B_3 , | ||
596 | NOTE_C_4 , NOTE_C_SHARP_4 , NOTE_D_4 , NOTE_D_SHARP_4 , | ||
597 | NOTE_E_4 , NOTE_F_4 , NOTE_F_SHARP_4 , NOTE_G_4 , | ||
598 | NOTE_G_SHARP_4 , NOTE_A_4 , NOTE_A_SHARP_4 , NOTE_B_4 , | ||
599 | NOTE_C_5 , NOTE_C_SHARP_5 , NOTE_D_5 , NOTE_D_SHARP_5 , | ||
600 | NOTE_E_5 , NOTE_F_5 , NOTE_F_SHARP_5 , NOTE_G_5 , | ||
601 | NOTE_G_SHARP_5 , NOTE_A_5 , NOTE_A_SHARP_5 , NOTE_B_5 , | ||
602 | NOTE_C_6 , NOTE_C_SHARP_6 , NOTE_D_6 , NOTE_D_SHARP_6 , | ||
603 | NOTE_E_6 , NOTE_F_6 , NOTE_F_SHARP_6 , NOTE_G_6 , | ||
604 | NOTE_G_SHARP_6 , NOTE_A_6 , NOTE_A_SHARP_6 , NOTE_B_6 , | ||
605 | NOTE_C_7 , NOTE_C_SHARP_7 , NOTE_D_7 , NOTE_D_SHARP_7 , | ||
606 | NOTE_E_7 , NOTE_F_7 , NOTE_F_SHARP_7 , NOTE_G_7 , | ||
607 | NOTE_G_SHARP_7 , NOTE_A_7 , NOTE_A_SHARP_7 , NOTE_B_7 , | ||
608 | NOTE_C_8 | ||
609 | } Note; | ||
610 | |||
611 | static const u32 sound_rates[] = { | ||
612 | 44 , 156 , 262 , 363 , 457 , 547 , 631 , 710 , 785 , 856 , 923 , 986 , | ||
613 | 1046, 1102, 1155, 1205, 1252, 1297, 1339, 1379, 1416, 1452, 1485, 1517, | ||
614 | 1547, 1575, 1601, 1626, 1650, 1672, 1693, 1713, 1732, 1750, 1766, 1782, | ||
615 | 1797, 1811, 1824, 1837, 1849, 1860, 1870, 1880, 1890, 1899, 1907, 1915, | ||
616 | 1922, 1929, 1936, 1942, 1948, 1954, 1959, 1964, 1969, 1973, 1977, 1981, | ||
617 | 1985, 1988, 1992, 1995, 1998, 2001, 2003, 2006, 2008, 2010, 2012, 2014, | ||
618 | 2016, | ||
619 | }; | ||
620 | |||
621 | // | ||
622 | // System control. | ||
623 | // | ||
624 | |||
625 | // Used to configure gamepak access timings. | ||
626 | #define SYSTEM_WAIT *((vu16*)(MEM_IO + 0x0204)) | ||
627 | |||
628 | // This register defaults to 0, but manufacture cartridges use the values | ||
629 | // provided below. | ||
630 | #define SYSTEM_WAIT_DEFAULT 0 | ||
631 | #define SYSTEM_WAIT_CARTRIDGE 0x4317 | ||
632 | |||
633 | // | ||
634 | // Misc. | ||
635 | // | ||
636 | |||
637 | // Custom VSync option. This will waste a lot of battery power, since the | ||
638 | // machine is not clocked down. Prefer using `bios_vblank_wait()` if interrupts | ||
639 | // are enabled. | ||
640 | static inline void | ||
641 | wait_vsync(void) { | ||
642 | while(DISP_VCOUNT >= 160); | ||
643 | while(DISP_VCOUNT < 160); | ||
644 | } | ||
645 | |||
646 | // General utility macros. | ||
647 | #define MIN(A, B) ((A) <= (B) ? (A) : (B)) | ||
648 | #define MAX(A, B) ((A) >= (B) ? (A) : (B)) | ||
649 | #define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X)) | ||
650 | #define LEN(ARR) (sizeof(ARR) / sizeof((ARR)[0])) | ||
651 | |||
652 | // Fixed-point arithmetic for (i.P) numbers. | ||
653 | #define FP_MUL(A,B,P) (((A) * (B)) >> (P)) | ||
654 | #define FP_DIV(A,B,P) (((A) << (P)) / (B)) | ||
655 | #define FP_LERP(Y0,Y1,X,P) ((Y0) + FP_MUL((X), ((Y1) - (Y0)), P)) | ||
656 | |||
657 | // | ||
658 | // Memory section macros for devkitARM. | ||
659 | // | ||
660 | |||
661 | #define IWRAM_DATA __attribute__((section(".iwram"))) | ||
662 | #define IWRAM_CODE __attribute__((section(".iwram"), long_call, target("arm"))) | ||
663 | #define EWRAM_DATA __attribute__((section(".ewram"))) | ||
664 | #define EWRAM_CODE __attribute__((section(".ewram"), long_call)) | ||
665 | #define EWRAM_BSS __attribute__((section(".sbss"))) | ||
666 | |||
667 | #endif // GBA_H | ||