summaryrefslogtreecommitdiff
path: root/gb.h
blob: 44f80b00872c3fd8e5ffe4ff0648f108b12394f0 (plain)
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
#ifndef GB_H
#define GB_H

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#include <stdint.h>

typedef enum {
  GB_CPU_STATE_RUN,
  GB_CPU_STATE_STOP,
  GB_CPU_STATE_HALT,
  GB_CPU_STATE_INVALID,
  GB_CPU_STATE_NOT_IMPLEMENTED,
  GB_CPU_STATE_LAST,
} gb_cpu_state_t;

#define GB_BTN_UP     1
#define GB_BTN_DOWN   (1 << 1)
#define GB_BTN_LEFT   (1 << 2)
#define GB_BTN_RIGHT  (1 << 3)
#define GB_BTN_A      (1 << 4)
#define GB_BTN_B      (1 << 5)
#define GB_BTN_SELECT (1 << 6)
#define GB_BTN_START  (1 << 7)

// frame size, in bytes
#define GB_FRAME_SIZE (3 * 160 * 144)

typedef struct {
  struct {
    // _Bool in_bios;

    // FIXME: combine these?
    uint8_t ram[0x2000]; // working ram (8k)
    uint8_t eram[65536]; // external ram (banked, up to 64k)
    uint8_t vram[0x2000]; // vram (8k)
    uint8_t oam[0xA0]; // oam (160 bytes)
    uint8_t zram[0x7F]; // zram (128 bytes)

    // rom (at least 32k)
    const uint8_t *rom;
    uint32_t rom_size;

    union {
      struct {
        // current rom bank (5 bits); see note about
        // rom_ram_mode below
        uint8_t rom_bank;

        // is external ram enabled?
        _Bool ram_enable;

        // ram bank
        // rom_ram_mode == 0: high two bits of rom bank
        // rom_ram_mode == 1: ram bank
        uint8_t ram_bank;

        // set interpretation of ram_bank
        _Bool rom_ram_mode;
      } mbc1;

      struct {
        // current rom bank (4 bits)
        uint8_t rom_bank;

        // is eram enabled?
        _Bool ram_enable;
      } mbc2;
    };

    // interrupts
    // ie: interrupt enable (addr: 0xFFFF)
    // iv: interrupt vector (addr: 0xFF0F)
    // (gb-manual, p26)
    uint8_t ie;
    uint8_t iv;

    // buttons (addr: 0xFF00)
    // gb-manual, p23
    uint8_t p1_mode;
    uint8_t btns;
  } mmu;

  struct {
    uint16_t clock;
    uint8_t mode,
            lcdc,
            stat,
            scy,
            scx,
            wy,
            wx,
            bgp,
            obp0,
            obp1,
            line,
            lyc;
    uint8_t rgb[GB_FRAME_SIZE];
    uint32_t frame;
  } gpu;

  struct {
    uint16_t div;
    uint32_t tima; // NOTE: cannot be uint16_t because of 10-bit shift
    uint8_t tma,
            tac;
  } timer;

  struct {
    uint16_t rs[6 /* RW_LAST */];
    uint32_t clock; /* FIXME: uint16_t? */
    gb_cpu_state_t state;

    // interrupt master enable
    _Bool ime;
  } cpu;
} gb_t;

void gb_init(gb_t * const, const uint8_t *rom, const uint32_t rom_size);
void gb_set_buttons(gb_t * const, const uint8_t);
void gb_frame(gb_t * const);
void gb_step(gb_t * const);
const uint8_t *gb_get_rgb_frame(const gb_t * const);

#ifdef __cplusplus
};
#endif /* __cplusplus */

#endif /* GB_H */