Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx/core/memz80.c
2 views
1
/***************************************************************************************
2
* Genesis Plus
3
* Z80 bus handlers (Genesis & Master System modes)
4
*
5
* Support for SG-1000, Mark-III, Master System, Game Gear & Mega Drive ports access
6
*
7
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
8
* Copyright (C) 2007-2011 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
45
/*--------------------------------------------------------------------------*/
46
/* Handlers for access to unused addresses and those which make the */
47
/* machine lock up. */
48
/*--------------------------------------------------------------------------*/
49
50
INLINE void z80_unused_w(unsigned int address, unsigned char data)
51
{
52
#ifdef LOGERROR
53
error("Z80 unused write %04X = %02X (%x)\n", address, data, Z80.pc.w.l);
54
#endif
55
}
56
57
INLINE unsigned char z80_unused_r(unsigned int address)
58
{
59
#ifdef LOGERROR
60
error("Z80 unused read %04X (%x)\n", address, Z80.pc.w.l);
61
#endif
62
return 0xFF;
63
}
64
65
INLINE void z80_lockup_w(unsigned int address, unsigned char data)
66
{
67
#ifdef LOGERROR
68
error("Z80 lockup write %04X = %02X (%x)\n", address, data, Z80.pc.w.l);
69
#endif
70
if (!config.force_dtack)
71
{
72
Z80.cycles = 0xFFFFFFFF;
73
zstate = 0;
74
}
75
}
76
77
INLINE unsigned char z80_lockup_r(unsigned int address)
78
{
79
#ifdef LOGERROR
80
error("Z80 lockup read %04X (%x)\n", address, Z80.pc.w.l);
81
#endif
82
if (!config.force_dtack)
83
{
84
Z80.cycles = 0xFFFFFFFF;
85
zstate = 0;
86
}
87
return 0xFF;
88
}
89
90
91
/*--------------------------------------------------------------------------*/
92
/* Z80 Memory handlers (Genesis mode) */
93
/*--------------------------------------------------------------------------*/
94
95
unsigned char z80_memory_r(unsigned int address)
96
{
97
switch((address >> 13) & 7)
98
{
99
case 0: /* $0000-$3FFF: Z80 RAM (8K mirrored) */
100
case 1:
101
{
102
return zram[address & 0x1FFF];
103
}
104
105
case 2: /* $4000-$5FFF: YM2612 */
106
{
107
return fm_read(Z80.cycles, address & 3);
108
}
109
110
case 3: /* $7F00-$7FFF: VDP */
111
{
112
if ((address >> 8) == 0x7F)
113
{
114
return (*zbank_memory_map[0xc0].read)(address);
115
}
116
return z80_unused_r(address);
117
}
118
119
default: /* $8000-$FFFF: 68k bank (32K) */
120
{
121
address = zbank | (address & 0x7FFF);
122
if (zbank_memory_map[address >> 16].read)
123
{
124
return (*zbank_memory_map[address >> 16].read)(address);
125
}
126
return READ_BYTE(m68k.memory_map[address >> 16].base, address & 0xFFFF);
127
}
128
}
129
}
130
131
132
void z80_memory_w(unsigned int address, unsigned char data)
133
{
134
switch((address >> 13) & 7)
135
{
136
case 0: /* $0000-$3FFF: Z80 RAM (8K mirrored) */
137
case 1:
138
{
139
zram[address & 0x1FFF] = data;
140
return;
141
}
142
143
case 2: /* $4000-$5FFF: YM2612 */
144
{
145
fm_write(Z80.cycles, address & 3, data);
146
return;
147
}
148
149
case 3: /* Bank register and VDP */
150
{
151
switch(address >> 8)
152
{
153
case 0x60: /* $6000-$60FF: Bank register */
154
{
155
gen_zbank_w(data & 1);
156
return;
157
}
158
159
case 0x7F: /* $7F00-$7FFF: VDP */
160
{
161
(*zbank_memory_map[0xc0].write)(address, data);
162
return;
163
}
164
165
default:
166
{
167
z80_unused_w(address, data);
168
return;
169
}
170
}
171
}
172
173
default: /* $8000-$FFFF: 68k bank (32K) */
174
{
175
address = zbank | (address & 0x7FFF);
176
if (zbank_memory_map[address >> 16].write)
177
{
178
(*zbank_memory_map[address >> 16].write)(address, data);
179
return;
180
}
181
WRITE_BYTE(m68k.memory_map[address >> 16].base, address & 0xFFFF, data);
182
return;
183
}
184
}
185
}
186
187
/*--------------------------------------------------------------------------*/
188
/* Unused Port handlers */
189
/* */
190
/* Ports are unused when not in Mark III compatibility mode. */
191
/* */
192
/* Genesis games that access ports anyway: */
193
/* Thunder Force IV reads port $BF in it's interrupt handler. */
194
/* */
195
/*--------------------------------------------------------------------------*/
196
197
unsigned char z80_unused_port_r(unsigned int port)
198
{
199
#if LOGERROR
200
error("Z80 unused read from port %04X (%x)\n", port, Z80.pc.w.l);
201
#endif
202
if (system_hw == SYSTEM_SMS)
203
{
204
unsigned int address = (Z80.pc.w.l - 1) & 0xFFFF;
205
return z80_readmap[address >> 10][address & 0x3FF];
206
}
207
return 0xFF;
208
}
209
210
void z80_unused_port_w(unsigned int port, unsigned char data)
211
{
212
#if LOGERROR
213
error("Z80 unused write to port %04X = %02X (%x)\n", port, data, Z80.pc.w.l);
214
#endif
215
}
216
217
/*--------------------------------------------------------------------------*/
218
/* MegaDrive / Genesis port handlers (Master System compatibility mode) */
219
/*--------------------------------------------------------------------------*/
220
221
void z80_md_port_w(unsigned int port, unsigned char data)
222
{
223
switch (port & 0xC1)
224
{
225
case 0x01:
226
{
227
io_z80_write(1, data, Z80.cycles + PBC_CYCLE_OFFSET);
228
return;
229
}
230
231
case 0x40:
232
case 0x41:
233
{
234
SN76489_Write(Z80.cycles, data);
235
return;
236
}
237
238
case 0x80:
239
{
240
vdp_z80_data_w(data);
241
return;
242
}
243
244
case 0x81:
245
{
246
vdp_z80_ctrl_w(data);
247
return;
248
}
249
250
default:
251
{
252
port &= 0xFF;
253
254
if ((port >= 0xF0) && (config.ym2413 & 1))
255
{
256
fm_write(Z80.cycles, port&3, data);
257
return;
258
}
259
260
z80_unused_port_w(port, data);
261
return;
262
}
263
}
264
}
265
266
unsigned char z80_md_port_r(unsigned int port)
267
{
268
switch (port & 0xC1)
269
{
270
case 0x40:
271
{
272
return ((vdp_hvc_r(Z80.cycles - 15) >> 8) & 0xFF);
273
}
274
275
case 0x41:
276
{
277
return (vdp_hvc_r(Z80.cycles - 15) & 0xFF);
278
}
279
280
case 0x80:
281
{
282
return vdp_z80_data_r();
283
}
284
285
case 0x81:
286
{
287
return vdp_z80_ctrl_r(Z80.cycles);
288
}
289
290
default:
291
{
292
port &= 0xFF;
293
294
if ((port == 0xC0) || (port == 0xC1) || (port == 0xDC) || (port == 0xDD))
295
{
296
return io_z80_read(port & 1);
297
}
298
299
/* read FM chip if enabled */
300
if ((port >= 0xF0) && (config.ym2413 & 1))
301
{
302
return YM2413Read(port & 3);
303
}
304
305
return z80_unused_port_r(port);
306
}
307
}
308
}
309
310
311
/*--------------------------------------------------------------------------*/
312
/* Game Gear port handlers */
313
/*--------------------------------------------------------------------------*/
314
315
void z80_gg_port_w(unsigned int port, unsigned char data)
316
{
317
switch(port & 0xC1)
318
{
319
case 0x00:
320
case 0x01:
321
{
322
port &= 0xFF;
323
324
if (port < 0x07)
325
{
326
if (system_hw == SYSTEM_GG)
327
{
328
io_gg_write(port, data);
329
return;
330
}
331
332
z80_unused_port_w(port & 0xFF, data);
333
return;
334
}
335
336
io_z80_write(port & 1, data, Z80.cycles + SMS_CYCLE_OFFSET);
337
return;
338
}
339
340
case 0x40:
341
case 0x41:
342
{
343
SN76489_Write(Z80.cycles, data);
344
return;
345
}
346
347
case 0x80:
348
{
349
vdp_z80_data_w(data);
350
return;
351
}
352
353
case 0x81:
354
{
355
vdp_sms_ctrl_w(data);
356
return;
357
}
358
359
default:
360
{
361
z80_unused_port_w(port & 0xFF, data);
362
return;
363
}
364
}
365
}
366
367
unsigned char z80_gg_port_r(unsigned int port)
368
{
369
switch(port & 0xC1)
370
{
371
case 0x00:
372
case 0x01:
373
{
374
port &= 0xFF;
375
376
if (port < 0x07)
377
{
378
if (system_hw == SYSTEM_GG)
379
{
380
return io_gg_read(port);
381
}
382
}
383
384
return z80_unused_port_r(port);
385
}
386
387
case 0x40:
388
{
389
return ((vdp_hvc_r(Z80.cycles) >> 8) & 0xFF);
390
}
391
392
case 0x41:
393
{
394
return (vdp_hvc_r(Z80.cycles) & 0xFF);
395
}
396
397
case 0x80:
398
{
399
return vdp_z80_data_r();
400
}
401
402
case 0x81:
403
{
404
return vdp_z80_ctrl_r(Z80.cycles);
405
}
406
407
default:
408
{
409
port &= 0xFF;
410
411
if ((port == 0xC0) || (port == 0xC1) || (port == 0xDC) || (port == 0xDD))
412
{
413
return io_z80_read(port & 1);
414
}
415
416
return z80_unused_port_r(port);
417
}
418
}
419
}
420
421
422
/*--------------------------------------------------------------------------*/
423
/* Master System port handlers */
424
/*--------------------------------------------------------------------------*/
425
426
void z80_ms_port_w(unsigned int port, unsigned char data)
427
{
428
switch (port & 0xC1)
429
{
430
case 0x00:
431
case 0x01:
432
{
433
io_z80_write(port & 1, data, Z80.cycles + SMS_CYCLE_OFFSET);
434
return;
435
}
436
437
case 0x40:
438
case 0x41:
439
{
440
SN76489_Write(Z80.cycles, data);
441
return;
442
}
443
444
case 0x80:
445
{
446
vdp_z80_data_w(data);
447
return;
448
}
449
450
case 0x81:
451
{
452
vdp_sms_ctrl_w(data);
453
return;
454
}
455
456
default:
457
{
458
if (!(port & 4) && (config.ym2413 & 1))
459
{
460
fm_write(Z80.cycles, port & 3, data);
461
return;
462
}
463
464
z80_unused_port_w(port & 0xFF, data);
465
return;
466
}
467
}
468
}
469
470
unsigned char z80_ms_port_r(unsigned int port)
471
{
472
switch (port & 0xC1)
473
{
474
case 0x00:
475
case 0x01:
476
{
477
return z80_unused_port_r(port & 0xFF);
478
}
479
480
case 0x40:
481
{
482
return ((vdp_hvc_r(Z80.cycles) >> 8) & 0xFF);
483
}
484
485
case 0x41:
486
{
487
return (vdp_hvc_r(Z80.cycles) & 0xFF);
488
}
489
490
case 0x80:
491
{
492
return vdp_z80_data_r();
493
}
494
495
case 0x81:
496
{
497
return vdp_z80_ctrl_r(Z80.cycles);
498
}
499
500
default:
501
{
502
/* read FM chip if enabled */
503
if (!(port & 4) && (config.ym2413 & 1))
504
{
505
/* check if I/O ports are disabled */
506
if (io_reg[0x0E] & 0x04)
507
{
508
return YM2413Read(port & 3);
509
}
510
else
511
{
512
return YM2413Read(port & 3) & io_z80_read(port & 1);
513
}
514
}
515
516
/* check if I/O ports are enabled */
517
if (!(io_reg[0x0E] & 0x04))
518
{
519
return io_z80_read(port & 1);
520
}
521
522
return z80_unused_port_r(port & 0xFF);
523
}
524
}
525
}
526
527
528
/*--------------------------------------------------------------------------*/
529
/* Mark III port handlers */
530
/*--------------------------------------------------------------------------*/
531
532
void z80_m3_port_w(unsigned int port, unsigned char data)
533
{
534
switch (port & 0xC1)
535
{
536
case 0x00:
537
case 0x01:
538
{
539
z80_unused_port_w(port, data);
540
return;
541
}
542
543
case 0x40:
544
case 0x41:
545
{
546
SN76489_Write(Z80.cycles, data);
547
return;
548
}
549
550
case 0x80:
551
{
552
vdp_z80_data_w(data);
553
return;
554
}
555
556
case 0x81:
557
{
558
vdp_sms_ctrl_w(data);
559
return;
560
}
561
562
default:
563
{
564
if (!(port & 4) && (config.ym2413 & 1))
565
{
566
fm_write(Z80.cycles, port & 3, data);
567
return;
568
}
569
570
z80_unused_port_w(port & 0xFF, data);
571
return;
572
}
573
}
574
}
575
576
unsigned char z80_m3_port_r(unsigned int port)
577
{
578
switch (port & 0xC1)
579
{
580
case 0x00:
581
case 0x01:
582
{
583
return z80_unused_port_r(port & 0xFF);
584
}
585
586
case 0x40:
587
{
588
return ((vdp_hvc_r(Z80.cycles) >> 8) & 0xFF);
589
}
590
591
case 0x41:
592
{
593
return (vdp_hvc_r(Z80.cycles) & 0xFF);
594
}
595
596
case 0x80:
597
{
598
return vdp_z80_data_r();
599
}
600
601
case 0x81:
602
{
603
return vdp_z80_ctrl_r(Z80.cycles);
604
}
605
606
default:
607
{
608
/* read FM chip if enabled */
609
if (!(port & 4) && (config.ym2413 & 1))
610
{
611
/* I/O ports are automatically disabled */
612
return YM2413Read(port & 3);
613
}
614
615
/* read I/O ports */
616
return io_z80_read(port & 1);
617
}
618
}
619
}
620
621
622
/*--------------------------------------------------------------------------*/
623
/* SG-1000 port handlers */
624
/*--------------------------------------------------------------------------*/
625
626
void z80_sg_port_w(unsigned int port, unsigned char data)
627
{
628
switch(port & 0xC1)
629
{
630
case 0x40:
631
case 0x41:
632
{
633
SN76489_Write(Z80.cycles, data);
634
return;
635
}
636
637
case 0x80:
638
{
639
vdp_z80_data_w(data);
640
return;
641
}
642
643
case 0x81:
644
{
645
vdp_tms_ctrl_w(data);
646
return;
647
}
648
649
default:
650
{
651
z80_unused_port_w(port & 0xFF, data);
652
return;
653
}
654
}
655
}
656
657
unsigned char z80_sg_port_r(unsigned int port)
658
{
659
switch (port & 0xC1)
660
{
661
case 0x80:
662
{
663
return vdp_z80_data_r();
664
}
665
666
case 0x81:
667
{
668
return vdp_z80_ctrl_r(Z80.cycles);
669
}
670
671
case 0xC0:
672
case 0xC1:
673
{
674
return io_z80_read(port & 1);
675
}
676
677
default:
678
{
679
return z80_unused_port_r(port);
680
}
681
}
682
}
683
684