summaryrefslogtreecommitdiffstats
path: root/src/common.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common.h')
-rw-r--r--src/common.h133
1 files changed, 132 insertions, 1 deletions
diff --git a/src/common.h b/src/common.h
index e3405be..dac48ad 100644
--- a/src/common.h
+++ b/src/common.h
@@ -46,6 +46,15 @@
46#define DISP_OBJ (1 << 12) 46#define DISP_OBJ (1 << 12)
47#define DISP_ENABLE_SPRITES DISP_OBJ | DISP_OBJ_1D 47#define DISP_ENABLE_SPRITES DISP_OBJ | DISP_OBJ_1D
48 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
49// Registers to control of BG layers. 58// Registers to control of BG layers.
50#define BG_CTRL(N) *((vu16*)(0x04000008 + 0x0002 * (N))) 59#define BG_CTRL(N) *((vu16*)(0x04000008 + 0x0002 * (N)))
51 60
@@ -245,8 +254,14 @@ u32 profile_stop(void) {
245// Input handling. 254// Input handling.
246// 255//
247 256
248// Memory address for key input register 257// Memory address for key input and control register
249#define KEY_INPUTS *((vu16*) 0x04000130) 258#define KEY_INPUTS *((vu16*) 0x04000130)
259#define KEY_CTRL *((vu16*) 0x04000132)
260
261// Key control register bits.
262#define KEY_IRQ_KEY(N) (N)
263#define KEY_IRQ (1 << 0xE)
264#define KEY_IRQ_IF_SET (1 << 0xF)
250 265
251// Alias for key pressing bits. 266// Alias for key pressing bits.
252#define KEY_A (1 << 0) 267#define KEY_A (1 << 0)
@@ -385,4 +400,120 @@ dma_fill(void *dst, const void *src, u32 size, int channel) {
385 dma_transfer_fill(dst, src, size / 4, channel, DMA_CHUNK_32 | DMA_ENABLE); 400 dma_transfer_fill(dst, src, size / 4, channel, DMA_CHUNK_32 | DMA_ENABLE);
386} 401}
387 402
403//
404// Interrupts.
405//
406
407#define IRQ_ENABLE *((vu16*) 0x04000200)
408#define IRQ_ACK *((vu16*) 0x04000202)
409#define IRQ_CTRL *((vu16*) 0x04000208)
410#define IRQ_ACK_BIOS *((vu16*) 0x03007FF8)
411
412typedef enum {
413 IRQ_VBLANK,
414 IRQ_HBLANK,
415 IRQ_VCOUNT,
416 IRQ_TIMER_0,
417 IRQ_TIMER_1,
418 IRQ_TIMER_2,
419 IRQ_TIMER_3,
420 IRQ_SERIAL,
421 IRQ_DMA_0,
422 IRQ_DMA_1,
423 IRQ_DMA_2,
424 IRQ_DMA_3,
425 IRQ_KEYPAD,
426 IRQ_GAMEPAK,
427} IrqIndex;
428
429typedef void (*IrsFunc)(void);
430
431IrsFunc irs_table[] = {
432 [IRQ_VBLANK ] = NULL,
433 [IRQ_HBLANK ] = NULL,
434 [IRQ_VCOUNT ] = NULL,
435 [IRQ_TIMER_0] = NULL,
436 [IRQ_TIMER_1] = NULL,
437 [IRQ_TIMER_2] = NULL,
438 [IRQ_TIMER_3] = NULL,
439 [IRQ_SERIAL ] = NULL,
440 [IRQ_DMA_0 ] = NULL,
441 [IRQ_DMA_1 ] = NULL,
442 [IRQ_DMA_2 ] = NULL,
443 [IRQ_DMA_3 ] = NULL,
444 [IRQ_KEYPAD ] = NULL,
445 [IRQ_GAMEPAK] = NULL,
446};
447
448void
449irq_enable(IrqIndex idx) {
450 switch (idx) {
451 case IRQ_VBLANK: { DISP_STATUS |= DISP_VBLANK_IRQ; } break;
452 case IRQ_HBLANK: { DISP_STATUS |= DISP_HBLANK_IRQ; } break;
453 case IRQ_VCOUNT: { DISP_STATUS |= DISP_VCOUNT_IRQ; } break;
454 case IRQ_TIMER_0: { TIMER_CTRL_0 |= TIMER_CTRL_IRQ; } break;
455 case IRQ_TIMER_1: { TIMER_CTRL_1 |= TIMER_CTRL_IRQ; } break;
456 case IRQ_TIMER_2: { TIMER_CTRL_2 |= TIMER_CTRL_IRQ; } break;
457 case IRQ_TIMER_3: { TIMER_CTRL_3 |= TIMER_CTRL_IRQ; } break;
458 case IRQ_SERIAL: { /* TODO: Set REG_SERIAL? */ } break;
459 case IRQ_DMA_0: { DMA_CTRL(0) |= DMA_IRQ; } break;
460 case IRQ_DMA_1: { DMA_CTRL(1) |= DMA_IRQ; } break;
461 case IRQ_DMA_2: { DMA_CTRL(2) |= DMA_IRQ; } break;
462 case IRQ_DMA_3: { DMA_CTRL(3) |= DMA_IRQ; } break;
463 case IRQ_KEYPAD: { KEY_CTRL |= KEY_IRQ; } break;
464 case IRQ_GAMEPAK: { /* Nothing to do here...*/ } break;
465 }
466 IRQ_ENABLE |= (1 << idx);
467}
468
469void
470irq_disable(IrqIndex idx) {
471 switch (idx) {
472 case IRQ_VBLANK: { DISP_STATUS &= ~DISP_VBLANK_IRQ; } break;
473 case IRQ_HBLANK: { DISP_STATUS &= ~DISP_HBLANK_IRQ; } break;
474 case IRQ_VCOUNT: { DISP_STATUS &= ~DISP_VCOUNT_IRQ; } break;
475 case IRQ_TIMER_0: { TIMER_CTRL_0 &= ~TIMER_CTRL_IRQ; } break;
476 case IRQ_TIMER_1: { TIMER_CTRL_1 &= ~TIMER_CTRL_IRQ; } break;
477 case IRQ_TIMER_2: { TIMER_CTRL_2 &= ~TIMER_CTRL_IRQ; } break;
478 case IRQ_TIMER_3: { TIMER_CTRL_3 &= ~TIMER_CTRL_IRQ; } break;
479 case IRQ_SERIAL: { /* TODO: Set REG_SERIAL? */ } break;
480 case IRQ_DMA_0: { DMA_CTRL(0) &= ~DMA_IRQ; } break;
481 case IRQ_DMA_1: { DMA_CTRL(1) &= ~DMA_IRQ; } break;
482 case IRQ_DMA_2: { DMA_CTRL(2) &= ~DMA_IRQ; } break;
483 case IRQ_DMA_3: { DMA_CTRL(3) &= ~DMA_IRQ; } break;
484 case IRQ_KEYPAD: { KEY_CTRL &= ~KEY_IRQ; } break;
485 case IRQ_GAMEPAK: { /* Nothing to do here...*/ } break;
486 }
487 IRQ_ENABLE &= ~(1 << idx);
488}
489
490void
491irs_set(IrqIndex idx, IrsFunc func) {
492 // Store IRQ_CTRL status and disable interrupts for now.
493 u16 irq_ctrl = IRQ_CTRL;
494 IRQ_CTRL = 0;
495
496 // Update the IRS table and enable/disable the given IRQ.
497 irs_table[idx] = func;
498 if (func == NULL) {
499 irq_disable(idx);
500 } else {
501 irq_enable(idx);
502 }
503
504 // Restore previous irq_ctrl.
505 IRQ_CTRL = irq_ctrl;
506}
507
508#define IRS_MAIN *(IrsFunc*)(0x03007FFC)
509
510// External irs_main function, has to be written in ARM assembly.
511void irs_main(void);
512
513void
514irq_init() {
515 IRS_MAIN = irs_main;
516 IRQ_CTRL = 1;
517}
518
388#endif // GBAEXP_COMMON_H 519#endif // GBAEXP_COMMON_H