Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx32/core/genesis.c
2 views
1
/***************************************************************************************
2
* Genesis Plus
3
* Internal Hardware & Bus controllers
4
*
5
* Support for SG-1000, Mark-III, Master System, Game Gear, Mega Drive & Mega CD hardware
6
*
7
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
8
* Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX)
9
*
10
* Redistribution and use of this code or any derivative works are permitted
11
* provided that the following conditions are met:
12
*
13
* - Redistributions may not be sold, nor may they be used in a commercial
14
* product or activity.
15
*
16
* - Redistributions that are modified from the original source must include the
17
* complete source code, including the source code for all components used by a
18
* binary built from the modified sources. However, as a special exception, the
19
* source code distributed need not include anything that is normally distributed
20
* (in either source or binary form) with the major components (compiler, kernel,
21
* and so on) of the operating system on which the executable runs, unless that
22
* component itself accompanies the executable.
23
*
24
* - Redistributions must reproduce the above copyright notice, this list of
25
* conditions and the following disclaimer in the documentation and/or other
26
* materials provided with the distribution.
27
*
28
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
32
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
* POSSIBILITY OF SUCH DAMAGE.
39
*
40
****************************************************************************************/
41
42
#include "shared.h"
43
44
external_t ext; /* External Hardware (Cartridge, CD unit, ...) */
45
uint8 boot_rom[0x800]; /* Genesis BOOT ROM */
46
uint8 work_ram[0x10000]; /* 68K RAM */
47
uint8 zram[0x2000]; /* Z80 RAM */
48
uint32 zbank; /* Z80 bank window address */
49
uint8 zstate; /* Z80 bus state (d0 = BUSACK, d1 = /RESET) */
50
uint8 pico_current; /* PICO current page */
51
52
uint8 tmss[4]; /* TMSS security register */
53
54
/*--------------------------------------------------------------------------*/
55
/* Init, reset, shutdown functions */
56
/*--------------------------------------------------------------------------*/
57
58
void gen_init(void)
59
{
60
int i;
61
62
/* initialize Z80 */
63
z80_init(0,z80_irq_callback);
64
65
/* 8-bit / 16-bit modes */
66
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
67
{
68
/* initialize main 68k */
69
m68k_init();
70
m68k.aerr_enabled = config.addr_error;
71
72
/* initialize main 68k memory map */
73
74
/* $800000-$DFFFFF : illegal access by default */
75
for (i=0x80; i<0xe0; i++)
76
{
77
m68k.memory_map[i].base = work_ram; /* for VDP DMA */
78
m68k.memory_map[i].read8 = m68k_lockup_r_8;
79
m68k.memory_map[i].read16 = m68k_lockup_r_16;
80
m68k.memory_map[i].write8 = m68k_lockup_w_8;
81
m68k.memory_map[i].write16 = m68k_lockup_w_16;
82
zbank_memory_map[i].read = zbank_lockup_r;
83
zbank_memory_map[i].write = zbank_lockup_w;
84
}
85
86
/* $C0xxxx, $C8xxxx, $D0xxxx, $D8xxxx : VDP ports */
87
for (i=0xc0; i<0xe0; i+=8)
88
{
89
m68k.memory_map[i].read8 = vdp_read_byte;
90
m68k.memory_map[i].read16 = vdp_read_word;
91
m68k.memory_map[i].write8 = vdp_write_byte;
92
m68k.memory_map[i].write16 = vdp_write_word;
93
zbank_memory_map[i].read = zbank_read_vdp;
94
zbank_memory_map[i].write = zbank_write_vdp;
95
}
96
97
/* $E00000-$FFFFFF : Work RAM (64k) */
98
for (i=0xe0; i<0x100; i++)
99
{
100
m68k.memory_map[i].base = work_ram;
101
m68k.memory_map[i].read8 = NULL;
102
m68k.memory_map[i].read16 = NULL;
103
m68k.memory_map[i].write8 = NULL;
104
m68k.memory_map[i].write16 = NULL;
105
106
/* Z80 can ONLY write to 68k RAM, not read it */
107
zbank_memory_map[i].read = zbank_unused_r;
108
zbank_memory_map[i].write = NULL;
109
}
110
111
if (system_hw == SYSTEM_PICO)
112
{
113
/* additional registers mapped to $800000-$80FFFF */
114
m68k.memory_map[0x80].read8 = pico_read_byte;
115
m68k.memory_map[0x80].read16 = pico_read_word;
116
m68k.memory_map[0x80].write8 = m68k_unused_8_w;
117
m68k.memory_map[0x80].write16 = m68k_unused_16_w;
118
119
/* there is no I/O area (Notaz) */
120
m68k.memory_map[0xa1].read8 = m68k_read_bus_8;
121
m68k.memory_map[0xa1].read16 = m68k_read_bus_16;
122
m68k.memory_map[0xa1].write8 = m68k_unused_8_w;
123
m68k.memory_map[0xa1].write16 = m68k_unused_16_w;
124
125
/* initialize page index (closed) */
126
pico_current = 0;
127
}
128
else
129
{
130
/* $A10000-$A1FFFF : I/O & Control registers */
131
m68k.memory_map[0xa1].read8 = ctrl_io_read_byte;
132
m68k.memory_map[0xa1].read16 = ctrl_io_read_word;
133
m68k.memory_map[0xa1].write8 = ctrl_io_write_byte;
134
m68k.memory_map[0xa1].write16 = ctrl_io_write_word;
135
zbank_memory_map[0xa1].read = zbank_read_ctrl_io;
136
zbank_memory_map[0xa1].write = zbank_write_ctrl_io;
137
138
/* initialize Z80 memory map */
139
/* $0000-$3FFF is mapped to Z80 RAM (8K mirrored) */
140
/* $4000-$FFFF is mapped to hardware but Z80 PC should never point there */
141
for (i=0; i<64; i++)
142
{
143
z80_readmap[i] = &zram[(i & 7) << 10];
144
}
145
146
/* initialize Z80 memory handlers */
147
z80_writemem = z80_memory_w;
148
z80_readmem = z80_memory_r;
149
150
/* initialize Z80 port handlers */
151
z80_writeport = z80_unused_port_w;
152
z80_readport = z80_unused_port_r;
153
}
154
155
/* $000000-$7FFFFF : external hardware area */
156
if (system_hw == SYSTEM_MCD)
157
{
158
/* initialize SUB-CPU */
159
s68k_init();
160
161
/* initialize CD hardware */
162
scd_init();
163
}
164
else
165
{
166
/* Cartridge hardware */
167
md_cart_init();
168
}
169
}
170
else
171
{
172
/* initialize cartridge hardware & Z80 memory handlers */
173
sms_cart_init();
174
175
/* initialize Z80 ports handlers */
176
switch (system_hw)
177
{
178
/* Master System compatibility mode */
179
case SYSTEM_PBC:
180
{
181
z80_writeport = z80_md_port_w;
182
z80_readport = z80_md_port_r;
183
break;
184
}
185
186
/* Game Gear hardware */
187
case SYSTEM_GG:
188
case SYSTEM_GGMS:
189
{
190
/* initialize cartridge hardware & Z80 memory handlers */
191
sms_cart_init();
192
193
/* initialize Z80 ports handlers */
194
z80_writeport = z80_gg_port_w;
195
z80_readport = z80_gg_port_r;
196
break;
197
}
198
199
/* Master SYstem hardware */
200
case SYSTEM_SMS:
201
case SYSTEM_SMS2:
202
{
203
z80_writeport = z80_ms_port_w;
204
z80_readport = z80_ms_port_r;
205
break;
206
}
207
208
/* Mark-III hardware */
209
case SYSTEM_MARKIII:
210
{
211
z80_writeport = z80_m3_port_w;
212
z80_readport = z80_m3_port_r;
213
break;
214
}
215
216
/* SG-1000 hardware */
217
case SYSTEM_SG:
218
{
219
z80_writeport = z80_sg_port_w;
220
z80_readport = z80_sg_port_r;
221
break;
222
}
223
}
224
}
225
}
226
227
void gen_reset(int hard_reset)
228
{
229
/* System Reset */
230
if (hard_reset)
231
{
232
/* clear RAM (TODO: use random bit patterns for all systems, like on real hardware) */
233
memset(work_ram, 0x00, sizeof (work_ram));
234
memset(zram, 0x00, sizeof (zram));
235
}
236
else
237
{
238
/* reset YM2612 (on hard reset, this is done by sound_reset) */
239
fm_reset(0);
240
}
241
242
/* 68k & Z80 could be anywhere in VDP frame (Bonkers, Eternal Champions, X-Men 2) */
243
m68k.cycles = Z80.cycles = 0; //(uint32)((MCYCLES_PER_LINE * lines_per_frame) * ((double)rand() / (double)RAND_MAX));
244
245
/* 68k cycles should be a multiple of 7 */
246
m68k.cycles = (m68k.cycles / 7) * 7;
247
248
/* Z80 cycles should be a multiple of 15 */
249
Z80.cycles = (Z80.cycles / 15) * 15;
250
251
/* 8-bit / 16-bit modes */
252
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
253
{
254
if (system_hw == SYSTEM_MCD)
255
{
256
/* FRES is only asserted on Power ON */
257
if (hard_reset)
258
{
259
/* reset CD hardware */
260
scd_reset(1);
261
}
262
}
263
264
/* reset MD cartridge hardware */
265
md_cart_reset(hard_reset);
266
267
/* Z80 bus is released & Z80 is reseted */
268
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
269
m68k.memory_map[0xa0].read16 = m68k_read_bus_16;
270
m68k.memory_map[0xa0].write8 = m68k_unused_8_w;
271
m68k.memory_map[0xa0].write16 = m68k_unused_16_w;
272
zstate = 0;
273
274
/* assume default bank is $000000-$007FFF */
275
zbank = 0;
276
277
/* TMSS support */
278
if ((config.bios & 1) && (system_hw == SYSTEM_MD) && hard_reset)
279
{
280
int i;
281
282
/* clear TMSS register */
283
memset(tmss, 0x00, sizeof(tmss));
284
285
/* VDP access is locked by default */
286
for (i=0xc0; i<0xe0; i+=8)
287
{
288
m68k.memory_map[i].read8 = m68k_lockup_r_8;
289
m68k.memory_map[i].read16 = m68k_lockup_r_16;
290
m68k.memory_map[i].write8 = m68k_lockup_w_8;
291
m68k.memory_map[i].write16 = m68k_lockup_w_16;
292
zbank_memory_map[i].read = zbank_lockup_r;
293
zbank_memory_map[i].write = zbank_lockup_w;
294
}
295
296
/* check if BOOT ROM is loaded */
297
if (system_bios & SYSTEM_MD)
298
{
299
/* save default cartridge slot mapping */
300
cart.base = m68k.memory_map[0].base;
301
302
/* BOOT ROM is mapped at $000000-$0007FF */
303
m68k.memory_map[0].base = boot_rom;
304
}
305
}
306
307
/* reset MAIN-CPU */
308
m68k_pulse_reset();
309
}
310
else
311
{
312
/* RAM state at power-on is undefined on some systems */
313
if ((system_hw == SYSTEM_MARKIII) || ((system_hw & SYSTEM_SMS) && (region_code == REGION_JAPAN_NTSC)))
314
{
315
/* some korean games rely on RAM to be initialized with values different from $00 or $ff */
316
memset(work_ram, 0xf0, sizeof(work_ram));
317
}
318
319
/* reset cartridge hardware */
320
sms_cart_reset();
321
322
/* halt 68k (/VRES is forced low) */
323
m68k_pulse_halt();
324
}
325
326
/* reset Z80 */
327
z80_reset();
328
329
/* some Z80 registers need to be initialized on Power ON */
330
if (hard_reset)
331
{
332
/* Power Base Converter specific */
333
if (system_hw == SYSTEM_PBC)
334
{
335
/* startup code logic (verified on real hardware): */
336
/* 21 01 E1 : LD HL, $E101
337
25 -- -- : DEC H
338
F9 -- -- : LD SP,HL
339
C7 -- -- : RST $00
340
01 01 -- : LD BC, $xx01
341
*/
342
Z80.hl.w.l = 0xE001;
343
Z80.sp.w.l = 0xDFFF;
344
Z80.r = 4;
345
}
346
347
/* Master System specific (when BIOS is disabled) */
348
else if ((system_hw & SYSTEM_SMS) && (!(config.bios & 1) || !(system_bios & SYSTEM_SMS)))
349
{
350
/* usually done by BIOS & required by some SMS games that don't initialize SP */
351
Z80.sp.w.l = 0xDFFF;
352
}
353
}
354
}
355
356
/*-----------------------------------------------------------------------*/
357
/* OS ROM / TMSS register control functions (Genesis mode) */
358
/*-----------------------------------------------------------------------*/
359
360
void gen_tmss_w(unsigned int offset, unsigned int data)
361
{
362
int i;
363
364
/* write TMSS register */
365
WRITE_WORD(tmss, offset, data);
366
367
/* VDP requires "SEGA" value to be written in TMSS register */
368
if (memcmp((char *)tmss, "SEGA", 4) == 0)
369
{
370
for (i=0xc0; i<0xe0; i+=8)
371
{
372
m68k.memory_map[i].read8 = vdp_read_byte;
373
m68k.memory_map[i].read16 = vdp_read_word;
374
m68k.memory_map[i].write8 = vdp_write_byte;
375
m68k.memory_map[i].write16 = vdp_write_word;
376
zbank_memory_map[i].read = zbank_read_vdp;
377
zbank_memory_map[i].write = zbank_write_vdp;
378
}
379
}
380
else
381
{
382
for (i=0xc0; i<0xe0; i+=8)
383
{
384
m68k.memory_map[i].read8 = m68k_lockup_r_8;
385
m68k.memory_map[i].read16 = m68k_lockup_r_16;
386
m68k.memory_map[i].write8 = m68k_lockup_w_8;
387
m68k.memory_map[i].write16 = m68k_lockup_w_16;
388
zbank_memory_map[i].read = zbank_lockup_r;
389
zbank_memory_map[i].write = zbank_lockup_w;
390
}
391
}
392
}
393
394
void gen_bankswitch_w(unsigned int data)
395
{
396
/* check if BOOT ROM is loaded */
397
if (system_bios & SYSTEM_MD)
398
{
399
if (data & 1)
400
{
401
/* enable cartridge ROM */
402
m68k.memory_map[0].base = cart.base;
403
}
404
else
405
{
406
/* enable internal BOOT ROM */
407
m68k.memory_map[0].base = boot_rom;
408
}
409
}
410
}
411
412
unsigned int gen_bankswitch_r(void)
413
{
414
/* check if BOOT ROM is loaded */
415
if (system_bios & SYSTEM_MD)
416
{
417
return (m68k.memory_map[0].base == cart.base);
418
}
419
420
return 0xff;
421
}
422
423
424
/*-----------------------------------------------------------------------*/
425
/* Z80 Bus controller chip functions (Genesis mode) */
426
/* ----------------------------------------------------------------------*/
427
428
void gen_zbusreq_w(unsigned int data, unsigned int cycles)
429
{
430
if (data) /* !ZBUSREQ asserted */
431
{
432
/* check if Z80 is going to be stopped */
433
if (zstate == 1)
434
{
435
/* resynchronize with 68k */
436
z80_run(cycles);
437
438
/* enable 68k access to Z80 bus */
439
m68k.memory_map[0xa0].read8 = z80_read_byte;
440
m68k.memory_map[0xa0].read16 = z80_read_word;
441
m68k.memory_map[0xa0].write8 = z80_write_byte;
442
m68k.memory_map[0xa0].write16 = z80_write_word;
443
}
444
445
/* update Z80 bus status */
446
zstate |= 2;
447
}
448
else /* !ZBUSREQ released */
449
{
450
/* check if Z80 is going to be restarted */
451
if (zstate == 3)
452
{
453
/* resynchronize with 68k */
454
Z80.cycles = cycles;
455
456
/* disable 68k access to Z80 bus */
457
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
458
m68k.memory_map[0xa0].read16 = m68k_read_bus_16;
459
m68k.memory_map[0xa0].write8 = m68k_unused_8_w;
460
m68k.memory_map[0xa0].write16 = m68k_unused_16_w;
461
}
462
463
/* update Z80 bus status */
464
zstate &= 1;
465
}
466
}
467
468
void gen_zreset_w(unsigned int data, unsigned int cycles)
469
{
470
if (data) /* !ZRESET released */
471
{
472
/* check if Z80 is going to be restarted */
473
if (zstate == 0)
474
{
475
/* resynchronize with 68k */
476
Z80.cycles = cycles;
477
478
/* reset Z80 & YM2612 */
479
z80_reset();
480
fm_reset(cycles);
481
}
482
483
/* check if 68k access to Z80 bus is granted */
484
else if (zstate == 2)
485
{
486
/* enable 68k access to Z80 bus */
487
m68k.memory_map[0xa0].read8 = z80_read_byte;
488
m68k.memory_map[0xa0].read16 = z80_read_word;
489
m68k.memory_map[0xa0].write8 = z80_write_byte;
490
m68k.memory_map[0xa0].write16 = z80_write_word;
491
492
/* reset Z80 & YM2612 */
493
z80_reset();
494
fm_reset(cycles);
495
}
496
497
/* update Z80 bus status */
498
zstate |= 1;
499
}
500
else /* !ZRESET asserted */
501
{
502
/* check if Z80 is going to be stopped */
503
if (zstate == 1)
504
{
505
/* resynchronize with 68k */
506
z80_run(cycles);
507
}
508
509
/* check if 68k had access to Z80 bus */
510
else if (zstate == 3)
511
{
512
/* disable 68k access to Z80 bus */
513
m68k.memory_map[0xa0].read8 = m68k_read_bus_8;
514
m68k.memory_map[0xa0].read16 = m68k_read_bus_16;
515
m68k.memory_map[0xa0].write8 = m68k_unused_8_w;
516
m68k.memory_map[0xa0].write16 = m68k_unused_16_w;
517
}
518
519
/* stop YM2612 */
520
fm_reset(cycles);
521
522
/* update Z80 bus status */
523
zstate &= 2;
524
}
525
}
526
527
void gen_zbank_w (unsigned int data)
528
{
529
zbank = ((zbank >> 1) | ((data & 1) << 23)) & 0xFF8000;
530
}
531
532
533
/*-----------------------------------------------------------------------*/
534
/* Z80 interrupt callback */
535
/* ----------------------------------------------------------------------*/
536
537
int z80_irq_callback (int param)
538
{
539
return -1;
540
}
541
542