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