summaryrefslogtreecommitdiff
path: root/gb.h
blob: 27e685a4ead46cd0c74b0c225b0b5f1e792c60cc (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
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
#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 buffer size, in bytes
#define GB_FB_SIZE (3 * 160 * 144)

typedef struct gb_t_ gb_t;

typedef struct {
  void (*on_set_rom_bank)(const gb_t *, const uint16_t);
  void (*on_set_ram_bank)(const gb_t *, const uint16_t);
  void (*on_vblank)(const gb_t *);
  void (*on_hblank)(const gb_t *);
  void (*on_set_cpu_state)(const gb_t *, const gb_cpu_state_t);
  void (*on_timer)(const gb_t *);
  void (*on_gpu_step)(const gb_t *);
  void (*on_gpu_set_mode)(const gb_t *, const uint8_t);
  void (*on_rst)(const gb_t *, const uint16_t);
  void (*on_mmu_rb)(const gb_t *, const uint16_t, const uint8_t);
  void (*on_mmu_wb)(const gb_t *, const uint16_t, const uint8_t);
  void (*on_oam_wb)(const gb_t *, const uint16_t, const uint8_t);
  void *cb_data;
} gb_config_t;

struct gb_t_ {
  const gb_config_t *config;

  struct {
    // _Bool in_bios;

    // FIXME: combine these?
    uint8_t ram[0x2000]; // working ram (8k)
    uint8_t eram[0x10000]; // external ram (banked, up to 64k)
    uint8_t vram[0x2000]; // vram (8k)
    uint8_t oam[0xA0]; // oam (160 bytes)
    uint8_t zram[0x80]; // 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;

    // frame buffer
    uint8_t fb[GB_FB_SIZE];

    // frame counter
    uint32_t frame;

    struct {
      int16_t x, y;
      uint8_t tile;
      bool priority,
           y_flip,
           x_flip,
           palette;
    } oam_cache[40];

    bool oam_dirty;
  } 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;
};

void gb_init(
  gb_t * const ctx,
  const gb_config_t * const config,
  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);
_Bool gb_disasm(gb_t * const, char * const, size_t * const);
const uint8_t *gb_get_frame(const gb_t * const);

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

#endif /* GB_H */