Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx32/core/io_ctrl.c
2 views
1
/***************************************************************************************
2
* Genesis Plus
3
* I/O controller (Genesis & Master System modes)
4
*
5
* Support for Master System (315-5216, 315-5237 & 315-5297), Game Gear & Mega Drive I/O chips
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
#include "gamepad.h"
44
#include "lightgun.h"
45
#include "mouse.h"
46
#include "activator.h"
47
#include "xe_a1p.h"
48
#include "teamplayer.h"
49
#include "paddle.h"
50
#include "sportspad.h"
51
52
uint8 io_reg[0x10];
53
54
uint8 region_code = REGION_USA;
55
56
static struct port_t
57
{
58
void (*data_w)(unsigned char data, unsigned char mask);
59
unsigned char (*data_r)(void);
60
} port[3];
61
62
static void dummy_write(unsigned char data, unsigned char mask)
63
{
64
}
65
66
static unsigned char dummy_read(void)
67
{
68
return 0x7F;
69
}
70
71
/*****************************************************************************
72
* I/O chip initialization *
73
* *
74
*****************************************************************************/
75
void io_init(void)
76
{
77
/* Initialize connected peripherals */
78
input_init();
79
80
/* Initialize IO Ports handlers & connected peripherals */
81
switch (input.system[0])
82
{
83
case SYSTEM_MS_GAMEPAD:
84
{
85
port[0].data_w = dummy_write;
86
port[0].data_r = gamepad_1_read;
87
break;
88
}
89
90
case SYSTEM_MD_GAMEPAD:
91
{
92
port[0].data_w = gamepad_1_write;
93
port[0].data_r = gamepad_1_read;
94
break;
95
}
96
97
case SYSTEM_MOUSE:
98
{
99
port[0].data_w = mouse_write;
100
port[0].data_r = mouse_read;
101
break;
102
}
103
104
case SYSTEM_ACTIVATOR:
105
{
106
port[0].data_w = activator_1_write;
107
port[0].data_r = activator_1_read;
108
break;
109
}
110
111
case SYSTEM_XE_A1P:
112
{
113
port[0].data_w = xe_a1p_1_write;
114
port[0].data_r = xe_a1p_1_read;
115
break;
116
}
117
118
case SYSTEM_WAYPLAY:
119
{
120
port[0].data_w = wayplay_1_write;
121
port[0].data_r = wayplay_1_read;
122
break;
123
}
124
125
case SYSTEM_TEAMPLAYER:
126
{
127
port[0].data_w = teamplayer_1_write;
128
port[0].data_r = teamplayer_1_read;
129
break;
130
}
131
132
case SYSTEM_LIGHTPHASER:
133
{
134
port[0].data_w = dummy_write;
135
port[0].data_r = phaser_1_read;
136
break;
137
}
138
139
case SYSTEM_PADDLE:
140
{
141
port[0].data_w = paddle_1_write;
142
port[0].data_r = paddle_1_read;
143
break;
144
}
145
146
case SYSTEM_SPORTSPAD:
147
{
148
port[0].data_w = sportspad_1_write;
149
port[0].data_r = sportspad_1_read;
150
break;
151
}
152
153
default:
154
{
155
port[0].data_w = dummy_write;
156
port[0].data_r = dummy_read;
157
break;
158
}
159
}
160
161
switch (input.system[1])
162
{
163
case SYSTEM_MS_GAMEPAD:
164
{
165
port[1].data_w = dummy_write;
166
port[1].data_r = gamepad_2_read;
167
break;
168
}
169
170
case SYSTEM_MD_GAMEPAD:
171
{
172
port[1].data_w = gamepad_2_write;
173
port[1].data_r = gamepad_2_read;
174
break;
175
}
176
177
case SYSTEM_MOUSE:
178
{
179
port[1].data_w = mouse_write;
180
port[1].data_r = mouse_read;
181
break;
182
}
183
184
case SYSTEM_XE_A1P:
185
{
186
port[1].data_w = xe_a1p_2_write;
187
port[1].data_r = xe_a1p_2_read;
188
break;
189
}
190
191
case SYSTEM_ACTIVATOR:
192
{
193
port[1].data_w = activator_2_write;
194
port[1].data_r = activator_2_read;
195
break;
196
}
197
198
case SYSTEM_MENACER:
199
{
200
port[1].data_w = dummy_write;
201
port[1].data_r = menacer_read;
202
break;
203
}
204
205
case SYSTEM_JUSTIFIER:
206
{
207
port[1].data_w = justifier_write;
208
port[1].data_r = justifier_read;
209
break;
210
}
211
212
case SYSTEM_WAYPLAY:
213
{
214
port[1].data_w = wayplay_2_write;
215
port[1].data_r = wayplay_2_read;
216
break;
217
}
218
219
case SYSTEM_TEAMPLAYER:
220
{
221
port[1].data_w = teamplayer_2_write;
222
port[1].data_r = teamplayer_2_read;
223
break;
224
}
225
226
case SYSTEM_LIGHTPHASER:
227
{
228
port[1].data_w = dummy_write;
229
port[1].data_r = phaser_2_read;
230
break;
231
}
232
233
case SYSTEM_PADDLE:
234
{
235
port[1].data_w = paddle_2_write;
236
port[1].data_r = paddle_2_read;
237
break;
238
}
239
240
case SYSTEM_SPORTSPAD:
241
{
242
port[1].data_w = sportspad_2_write;
243
port[1].data_r = sportspad_2_read;
244
break;
245
}
246
247
default:
248
{
249
port[1].data_w = dummy_write;
250
port[1].data_r = dummy_read;
251
break;
252
}
253
}
254
255
/* External Port (unconnected) */
256
port[2].data_w = dummy_write;
257
port[2].data_r = dummy_read;
258
}
259
260
261
void io_reset(void)
262
{
263
/* Reset I/O registers */
264
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
265
{
266
io_reg[0x00] = region_code | (config.bios & 1);
267
io_reg[0x01] = 0x00;
268
io_reg[0x02] = 0x00;
269
io_reg[0x03] = 0x00;
270
io_reg[0x04] = 0x00;
271
io_reg[0x05] = 0x00;
272
io_reg[0x06] = 0x00;
273
io_reg[0x07] = 0xFF;
274
io_reg[0x08] = 0x00;
275
io_reg[0x09] = 0x00;
276
io_reg[0x0A] = 0xFF;
277
io_reg[0x0B] = 0x00;
278
io_reg[0x0C] = 0x00;
279
io_reg[0x0D] = 0xFB;
280
io_reg[0x0E] = 0x00;
281
io_reg[0x0F] = 0x00;
282
283
/* CD unit detection */
284
if (system_hw != SYSTEM_MCD)
285
{
286
io_reg[0x00] |= 0x20;
287
}
288
}
289
else
290
{
291
/* Game Gear specific registers */
292
io_reg[0x00] = 0x80 | (region_code >> 1);
293
io_reg[0x01] = 0x00;
294
io_reg[0x02] = 0xFF;
295
io_reg[0x03] = 0x00;
296
io_reg[0x04] = 0xFF;
297
io_reg[0x05] = 0x00;
298
io_reg[0x06] = 0xFF;
299
300
/* initial !RESET input */
301
io_reg[0x0D] = IO_RESET_HI;
302
303
/* default !CONT input */
304
if (system_hw != SYSTEM_PBC)
305
{
306
io_reg[0x0D] |= IO_CONT1_HI;
307
}
308
309
/* Control registers */
310
io_reg[0x0E] = 0x00;
311
io_reg[0x0F] = 0xFF;
312
}
313
314
/* Reset connected peripherals */
315
input_reset();
316
}
317
318
319
/*****************************************************************************
320
* I/O ports access from 68k (Genesis mode) *
321
* *
322
*****************************************************************************/
323
324
void io_68k_write(unsigned int offset, unsigned int data)
325
{
326
switch (offset)
327
{
328
case 0x01: /* Port A Data */
329
case 0x02: /* Port B Data */
330
case 0x03: /* Port C Data */
331
{
332
io_reg[offset] = data;
333
port[offset-1].data_w(data, io_reg[offset + 3]);
334
return;
335
}
336
337
case 0x04: /* Port A Ctrl */
338
case 0x05: /* Port B Ctrl */
339
case 0x06: /* Port C Ctrl */
340
{
341
if (data != io_reg[offset])
342
{
343
io_reg[offset] = data;
344
port[offset-4].data_w(io_reg[offset-3], data);
345
}
346
return;
347
}
348
349
case 0x07: /* Port A TxData */
350
case 0x0A: /* Port B TxData */
351
case 0x0D: /* Port C TxData */
352
{
353
io_reg[offset] = data;
354
return;
355
}
356
357
case 0x09: /* Port A S-Ctrl */
358
case 0x0C: /* Port B S-Ctrl */
359
case 0x0F: /* Port C S-Ctrl */
360
{
361
io_reg[offset] = data & 0xF8;
362
return;
363
}
364
365
default: /* Read-only ports */
366
{
367
return;
368
}
369
}
370
}
371
372
unsigned int io_68k_read(unsigned int offset)
373
{
374
switch(offset)
375
{
376
case 0x01: /* Port A Data */
377
case 0x02: /* Port B Data */
378
case 0x03: /* Port C Data */
379
{
380
unsigned int mask, data;
381
real_input_callback();
382
mask = 0x80 | io_reg[offset + 3];
383
data = port[offset-1].data_r();
384
return (io_reg[offset] & mask) | (data & ~mask);
385
}
386
387
default: /* return register value */
388
{
389
return io_reg[offset];
390
}
391
}
392
}
393
394
395
/*****************************************************************************
396
* I/O ports access from Z80 *
397
* *
398
*****************************************************************************/
399
400
void io_z80_write(unsigned int offset, unsigned int data, unsigned int cycles)
401
{
402
if (offset)
403
{
404
/* I/O Control register */
405
if (region_code & REGION_USA)
406
{
407
/*
408
Bit Function
409
--------------
410
D7 : Port B TH pin output level (1=high, 0=low)
411
D6 : Port B TR pin output level (1=high, 0=low)
412
D5 : Port A TH pin output level (1=high, 0=low)
413
D4 : Port A TR pin output level (1=high, 0=low)
414
D3 : Port B TH pin direction (1=input, 0=output)
415
D2 : Port B TR pin direction (1=input, 0=output)
416
D1 : Port A TH pin direction (1=input, 0=output)
417
D0 : Port A TR pin direction (1=input, 0=output)
418
*/
419
420
/* Send TR/TH state to connected peripherals */
421
port[0].data_w((data << 1) & 0x60, (~io_reg[0x0F] << 5) & 0x60);
422
port[1].data_w((data >> 1) & 0x60, (~io_reg[0x0F] << 3) & 0x60);
423
424
425
/* Check for TH low-to-high transitions on both ports */
426
if ((!(io_reg[0x0F] & 0x80) && (data & 0x80)) ||
427
(!(io_reg[0x0F] & 0x20) && (data & 0x20)))
428
{
429
/* Latch new HVC */
430
hvc_latch = hctab[cycles % MCYCLES_PER_LINE] | 0x10000;
431
}
432
433
/* Update I/O Control register */
434
io_reg[0x0F] = data;
435
}
436
else
437
{
438
/* TH output is fixed to 0 & TR is always an input on japanese hardware */
439
io_reg[0x0F] = (data | 0x05) & 0x5F;
440
441
/* Port $DD bits D4-D5 return D0-D2 (cf. http://www2.odn.ne.jp/~haf09260/Sms/EnrSms.htm) */
442
io_reg[0x0D] = ((data & 0x01) << 4) | ((data & 0x04) << 3);
443
}
444
}
445
else
446
{
447
/* Update Memory Control register */
448
io_reg[0x0E] = data;
449
450
/* Switch cartridge & BIOS ROM */
451
sms_cart_switch(~data);
452
}
453
}
454
455
unsigned int io_z80_read(unsigned int offset)
456
{
457
unsigned int data, ctrl;
458
real_input_callback();
459
/* Read port A & port B input data */
460
data = (port[0].data_r()) | (port[1].data_r() << 8);
461
462
/* I/O control register value */
463
ctrl = io_reg[0x0F];
464
465
/* I/O ports */
466
if (offset)
467
{
468
/*
469
Bit Function
470
--------------
471
D7 : Port B TH pin input
472
D6 : Port A TH pin input
473
D5 : CONT input (0 on Mega Drive hardware, 1 otherwise)
474
D4 : RESET button (1: default, 0: pressed, only on Master System hardware)
475
D3 : Port B TR pin input
476
D2 : Port B TL pin input
477
D1 : Port B Right pin input
478
D0 : Port B Left pin input
479
*/
480
data = ((data >> 10) & 0x0F) | (data & 0x40) | ((data >> 7) & 0x80) | io_reg[0x0D];
481
482
/* clear !RESET input */
483
io_reg[0x0D] |= IO_RESET_HI;
484
485
/* Adjust port B TH state if configured as output */
486
if (!(ctrl & 0x08))
487
{
488
data &= ~0x80;
489
data |= (ctrl & 0x80);
490
}
491
492
/* Adjust port A TH state if configured as output */
493
if (!(ctrl & 0x02))
494
{
495
data &= ~0x40;
496
data |= ((ctrl & 0x20) << 1);
497
}
498
499
/* Adjust port B TR state if configured as output */
500
if (!(ctrl & 0x04))
501
{
502
data &= ~0x08;
503
data |= ((ctrl & 0x40) >> 3);
504
}
505
}
506
else
507
{
508
/*
509
Bit Function
510
--------------
511
D7 : Port B Down pin input
512
D6 : Port B Up pin input
513
D5 : Port A TR pin input
514
D4 : Port A TL pin input
515
D3 : Port A Right pin input
516
D2 : Port A Left pin input
517
D1 : Port A Down pin input
518
D0 : Port A Up pin input
519
*/
520
data = (data & 0x3F) | ((data >> 2) & 0xC0);
521
522
/* Adjust port A TR state if configured as output */
523
if (!(ctrl & 0x01))
524
{
525
data &= ~0x20;
526
data |= ((ctrl & 0x10) << 1);
527
}
528
}
529
530
return data;
531
}
532
533
534
/*****************************************************************************
535
* Game Gear communication ports access *
536
* *
537
*****************************************************************************/
538
539
void io_gg_write(unsigned int offset, unsigned int data)
540
{
541
switch (offset)
542
{
543
case 1: /* Parallel data register */
544
io_reg[1] = data;
545
return;
546
547
case 2: /* Data direction register and NMI enable */
548
io_reg[2] = data;
549
return;
550
551
case 3: /* Transmit data buffer */
552
io_reg[3] = data;
553
return;
554
555
case 5: /* Serial control (bits 0-2 are read-only) */
556
io_reg[5] = data & 0xF8;
557
return;
558
559
case 6: /* PSG Stereo output control */
560
io_reg[6] = data;
561
SN76489_Config(Z80.cycles, config.psg_preamp, config.psgBoostNoise, data);
562
return;
563
564
default: /* Read-only */
565
return;
566
}
567
}
568
569
unsigned int io_gg_read(unsigned int offset)
570
{
571
switch (offset)
572
{
573
case 0: /* Mode Register */
574
return (io_reg[0] & ~(input.pad[0] & INPUT_START));
575
576
case 1: /* Parallel data register (not connected) */
577
return ((io_reg[1] & ~(io_reg[2] & 0x7F)) | (io_reg[2] & 0x7F));
578
579
case 2: /* Data direction register and NMI enable */
580
return io_reg[2];
581
582
case 3: /* Transmit data buffer */
583
return io_reg[3];
584
585
case 4: /* Receive data buffer */
586
return io_reg[4];
587
588
case 5: /* Serial control */
589
return io_reg[5];
590
591
default: /* Write-Only */
592
return 0xFF;
593
}
594
}
595
596
597