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
|
#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 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 *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[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;
};
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_rgb_frame(const gb_t * const);
#ifdef __cplusplus
};
#endif /* __cplusplus */
#endif /* GB_H */
|