-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
clownmdemu.h
291 lines (247 loc) · 7.79 KB
/
clownmdemu.h
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#ifndef CLOWNMDEMU_H
#define CLOWNMDEMU_H
#include <stdarg.h>
#include <stddef.h>
#include "clowncommon/clowncommon.h"
#include "clown68000/interpreter/clown68000.h"
#include "controller.h"
#include "fm.h"
#include "io-port.h"
#include "pcm.h"
#include "psg.h"
#include "vdp.h"
#include "z80.h"
#ifdef __cplusplus
extern "C" {
#endif
/* TODO - Documentation */
#define CLOWNMDEMU_PARAMETERS_INITIALISE(CONFIGURATION, CONSTANT, STATE, CALLBACKS) { \
(CONFIGURATION), \
(CONSTANT), \
(STATE), \
(CALLBACKS), \
\
&(STATE)->m68k.state, \
\
{ \
&(CONSTANT)->z80, \
&(STATE)->z80.state \
}, \
\
&(STATE)->mega_cd.m68k.state, \
\
{ \
&(CONFIGURATION)->vdp, \
&(CONSTANT)->vdp, \
&(STATE)->vdp \
}, \
\
FM_PARAMETERS_INITIALISE( \
&(CONFIGURATION)->fm, \
&(CONSTANT)->fm, \
&(STATE)->fm \
), \
\
{ \
&(CONFIGURATION)->psg, \
&(CONSTANT)->psg, \
&(STATE)->psg \
}, \
\
{ \
&(CONFIGURATION)->pcm, \
&(STATE)->mega_cd.pcm \
} \
}
/* Mega Drive */
#define CLOWNMDEMU_MASTER_CLOCK_NTSC 53693175
#define CLOWNMDEMU_MASTER_CLOCK_PAL 53203424
#define CLOWNMDEMU_M68K_CLOCK_DIVIDER 7
#define CLOWNMDEMU_M68K_CLOCK_NTSC (CLOWNMDEMU_MASTER_CLOCK_NTSC / CLOWNMDEMU_M68K_CLOCK_DIVIDER)
#define CLOWNMDEMU_M68K_CLOCK_PAL (CLOWNMDEMU_MASTER_CLOCK_PAL / CLOWNMDEMU_M68K_CLOCK_DIVIDER)
#define CLOWNMDEMU_Z80_CLOCK_DIVIDER 15
#define CLOWNMDEMU_Z80_CLOCK_NTSC (CLOWNMDEMU_MASTER_CLOCK_NTSC / CLOWNMDEMU_Z80_CLOCK_DIVIDER)
#define CLOWNMDEMU_Z80_CLOCK_PAL (CLOWNMDEMU_MASTER_CLOCK_PAL / CLOWNMDEMU_Z80_CLOCK_DIVIDER)
#define CLOWNMDEMU_FM_SAMPLE_RATE_NTSC (CLOWNMDEMU_M68K_CLOCK_NTSC / FM_SAMPLE_RATE_DIVIDER)
#define CLOWNMDEMU_FM_SAMPLE_RATE_PAL (CLOWNMDEMU_M68K_CLOCK_PAL / FM_SAMPLE_RATE_DIVIDER)
#define CLOWNMDEMU_PSG_SAMPLE_RATE_DIVIDER 16
#define CLOWNMDEMU_PSG_SAMPLE_RATE_NTSC (CLOWNMDEMU_Z80_CLOCK_NTSC / CLOWNMDEMU_PSG_SAMPLE_RATE_DIVIDER)
#define CLOWNMDEMU_PSG_SAMPLE_RATE_PAL (CLOWNMDEMU_Z80_CLOCK_PAL / CLOWNMDEMU_PSG_SAMPLE_RATE_DIVIDER)
/* Mega CD */
#define CLOWNMDEMU_MCD_MASTER_CLOCK 50000000
#define CLOWNMDEMU_MCD_M68K_CLOCK_DIVIDER 4
#define CLOWNMDEMU_MCD_M68K_CLOCK (CLOWNMDEMU_MCD_MASTER_CLOCK / CLOWNMDEMU_MCD_M68K_CLOCK_DIVIDER)
#define CLOWNMDEMU_PCM_SAMPLE_RATE_DIVIDER 0x180
#define CLOWNMDEMU_PCM_SAMPLE_RATE (CLOWNMDEMU_MCD_M68K_CLOCK / CLOWNMDEMU_PCM_SAMPLE_RATE_DIVIDER)
/* The NTSC framerate is 59.94FPS (60 divided by 1.001) */
#define CLOWNMDEMU_MULTIPLY_BY_NTSC_FRAMERATE(x) ((x) * (60 * 1000) / 1001)
#define CLOWNMDEMU_DIVIDE_BY_NTSC_FRAMERATE(x) (((x) / 60) + ((x) / (60 * 1000)))
/* The PAL framerate is 50FPS */
#define CLOWNMDEMU_MULTIPLY_BY_PAL_FRAMERATE(x) ((x) * 50)
#define CLOWNMDEMU_DIVIDE_BY_PAL_FRAMERATE(x) ((x) / 50)
typedef enum ClownMDEmu_Button
{
CLOWNMDEMU_BUTTON_UP,
CLOWNMDEMU_BUTTON_DOWN,
CLOWNMDEMU_BUTTON_LEFT,
CLOWNMDEMU_BUTTON_RIGHT,
CLOWNMDEMU_BUTTON_A,
CLOWNMDEMU_BUTTON_B,
CLOWNMDEMU_BUTTON_C,
CLOWNMDEMU_BUTTON_X,
CLOWNMDEMU_BUTTON_Y,
CLOWNMDEMU_BUTTON_Z,
CLOWNMDEMU_BUTTON_START,
CLOWNMDEMU_BUTTON_MODE,
CLOWNMDEMU_BUTTON_MAX
} ClownMDEmu_Button;
typedef enum ClownMDEmu_Region
{
CLOWNMDEMU_REGION_DOMESTIC, /* Japanese */
CLOWNMDEMU_REGION_OVERSEAS /* Elsewhere */
} ClownMDEmu_Region;
typedef enum ClownMDEmu_TVStandard
{
CLOWNMDEMU_TV_STANDARD_NTSC, /* 60Hz */
CLOWNMDEMU_TV_STANDARD_PAL /* 50Hz */
} ClownMDEmu_TVStandard;
typedef enum ClownMDEmu_CDDAMode
{
CLOWNMDEMU_CDDA_PLAY_ALL,
CLOWNMDEMU_CDDA_PLAY_ONCE,
CLOWNMDEMU_CDDA_PLAY_REPEAT
} ClownMDEmu_CDDAMode;
typedef struct ClownMDEmu_Configuration
{
struct
{
ClownMDEmu_Region region;
ClownMDEmu_TVStandard tv_standard;
} general;
VDP_Configuration vdp;
FM_Configuration fm;
PSG_Configuration psg;
PCM_Configuration pcm;
} ClownMDEmu_Configuration;
typedef struct ClownMDEmu_Constant
{
Z80_Constant z80;
VDP_Constant vdp;
FM_Constant fm;
PSG_Constant psg;
} ClownMDEmu_Constant;
typedef struct ClownMDEmu_State
{
struct
{
Clown68000_State state;
cc_u16l ram[0x8000];
cc_u32l cycle_countdown;
} m68k;
struct
{
Z80_State state;
cc_u8l ram[0x2000];
cc_u32l cycle_countdown;
cc_u16l bank;
cc_bool bus_requested;
cc_bool reset_held;
} z80;
VDP_State vdp;
FM_State fm;
PSG_State psg;
IOPort io_ports[3];
Controller controllers[2];
cc_u16l current_scanline;
struct
{
struct
{
Clown68000_State state;
cc_u32l cycle_countdown;
cc_bool bus_requested;
cc_bool reset_held;
} m68k;
struct
{
cc_u16l buffer[0x40000];
cc_u8l bank;
} prg_ram;
struct
{
cc_u16l buffer[0x20000];
cc_bool in_1m_mode;
cc_bool dmna, ret;
} word_ram;
struct
{
cc_u16l flag;
cc_u16l command[8]; /* The MAIN-CPU one. */
cc_u16l status[8]; /* The SUB-CPU one. */
} communication;
struct
{
cc_u32l current_sector, total_buffered_sectors;
cc_u8l cdc_delay;
cc_bool cdc_ready;
} cd;
struct
{
cc_bool enabled[6];
cc_bool irq1_pending;
cc_u32l irq3_countdown, irq3_countdown_master;
} irq;
struct
{
cc_bool playing, paused;
} cdda;
PCM_State pcm;
cc_bool boot_from_cd;
cc_u16l hblank_address;
cc_u16l delayed_dma_word;
} mega_cd;
} ClownMDEmu_State;
struct ClownMDEmu;
typedef struct ClownMDEmu_Callbacks
{
const void *user_data;
/* TODO: Rename these to be less mind-numbing. */
cc_u8f (*cartridge_read)(void *user_data, cc_u32f address);
void (*cartridge_written)(void *user_data, cc_u32f address, cc_u8f value);
void (*colour_updated)(void *user_data, cc_u16f index, cc_u16f colour);
void (*scanline_rendered)(void *user_data, cc_u16f scanline, const cc_u8l *pixels, cc_u16f screen_width, cc_u16f screen_height);
cc_bool (*input_requested)(void *user_data, cc_u8f player_id, ClownMDEmu_Button button_id);
void (*fm_audio_to_be_generated)(void *user_data, const struct ClownMDEmu *clownmdemu, size_t total_frames, void (*generate_fm_audio)(const struct ClownMDEmu *clownmdemu, cc_s16l *sample_buffer, size_t total_frames));
void (*psg_audio_to_be_generated)(void *user_data, const struct ClownMDEmu *clownmdemu, size_t total_frames, void (*generate_psg_audio)(const struct ClownMDEmu *clownmdemu, cc_s16l *sample_buffer, size_t total_frames));
void (*pcm_audio_to_be_generated)(void *user_data, const struct ClownMDEmu *clownmdemu, size_t total_frames, void (*generate_pcm_audio)(const struct ClownMDEmu *clownmdemu, cc_s16l *sample_buffer, size_t total_frames));
void (*cdda_audio_to_be_generated)(void *user_data, const struct ClownMDEmu *clownmdemu, size_t total_frames, void (*generate_cdda_audio)(const struct ClownMDEmu *clownmdemu, cc_s16l *sample_buffer, size_t total_frames));
void (*cd_seeked)(void *user_data, cc_u32f sector_index);
const cc_u8l* (*cd_sector_read)(void *user_data);
cc_bool (*cd_track_seeked)(void *user_data, cc_u16f track_index, ClownMDEmu_CDDAMode mode);
size_t (*cd_audio_read)(void *user_data, cc_s16l *sample_buffer, size_t total_frames);
} ClownMDEmu_Callbacks;
typedef struct ClownMDEmu
{
const ClownMDEmu_Configuration *configuration;
const ClownMDEmu_Constant *constant;
ClownMDEmu_State *state;
const ClownMDEmu_Callbacks *callbacks;
Clown68000_State *m68k;
Z80 z80;
Clown68000_State *mcd_m68k;
VDP vdp;
FM fm;
PSG psg;
PCM pcm;
} ClownMDEmu;
typedef void (*ClownMDEmu_LogCallback)(void *user_data, const char *format, va_list arg);
void ClownMDEmu_Constant_Initialise(ClownMDEmu_Constant *constant);
void ClownMDEmu_State_Initialise(ClownMDEmu_State *state);
void ClownMDEmu_Parameters_Initialise(ClownMDEmu *clownmdemu, const ClownMDEmu_Configuration *configuration, const ClownMDEmu_Constant *constant, ClownMDEmu_State *state, const ClownMDEmu_Callbacks *callbacks);
void ClownMDEmu_Iterate(const ClownMDEmu *clownmdemu);
void ClownMDEmu_Reset(const ClownMDEmu *clownmdemu, const cc_bool cd_boot);
void ClownMDEmu_SetLogCallback(const ClownMDEmu_LogCallback log_callback, const void *user_data);
#ifdef __cplusplus
}
#endif
#endif /* CLOWNMDEMU_H */