/
segas24.cpp
2588 lines (2193 loc) · 104 KB
/
segas24.cpp
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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert
/*
* Sega System 24
*
* Kudos to Charles MacDonald (http://cgfm2.emuviews.com) for his
* very useful research
*
* 3 Player controls for Gain Ground added by 'Unknown'
*/
/* Missing:
- linescroll in special modes (qgh title, mahmajn2/qrouka attract mode)
- screen flipping (mix register 13 & 2)
- FRC timer IRQ is currently in a slight off-beat (timer should be reset every time
that the mode changes, but current MAME framework doesn't seem to like it)
*/
/*
Sega System24 Overview
Sega, 1987-1994
PCB Layout
----------
Note: The differences in the revisions is just the use of different sized RAMs
and the quantities of RAM used.
(1st Revision)
837-6442 SYSTEM 24 (C)SEGA 1987
|-------------------------------------------------------------------------------|
| YM2151 DSW1 EPRxxxxx.IC1 --------------------------| TMM41464-10 |
| DSW2 EPRxxxxx.IC2 |-------------------------- TMM41464-10 |
| CN2 TMM41464-10 |
| 68000 |---------| TMM41464-10 |
| |---------| |--------------| | 315-5295| TMM41464-10 |
| | 315-5296| |HITACHI FD1094| |(QFP100) | TMM41464-10 |
|-| |(QFP100) | |317-0xxx-0xx | | | TMM41464-10 |
| | | |--------------| |---------| TMM41464-10 |
|-| |---------| MB81C466-10 |
| MB81C466-10 |
| |---------| MB81C466-10 |
|S |---------| | 315-5295| MB81C466-10 |
|E 20MHz | 315-5295| |(QFP100) | MB81C466-10 |
|G |(QFP100) | | | MB81C466-10 |
|A | | |---------| MB81C466-10 |
| |---------| MB81C466-10 |
|5 |---------| |
|6 |---------| |---------| | 315-5293| |
| | 315-5294| | 315-5292| | (QFP160)| |
| |(QFP100) | | (QFP160)| 32MHz | | |
| MB81C78A-45 | | | | |---------| |
|-| MB81C78A-45 |---------| |---------|M5M4464-12 x4 MB81461-12 x6 |
| |
|-| YM3012 |
| |--------| |
| |315-5242| HM65256 HM65256 HM65256 M5M4464-12 x4 MB81461-12 x6 |
| |(QFP44) | HM65256 HM65256 HM65256 |
|------------|--------|---------------------------------------------------------|
(2nd Revision)
837-6442-01 SYSTEM 24 (C) SEGA 1987
|-------------------------------------------------------------------------------|
| YM2151 DSW1 EPRxxxxx.IC1 --------------------------| TMM41464-10 |
| DSW2 EPRxxxxx.IC2 |-------------------------- TMM41464-10 |
| CN2 TMM41464-10 |
| 68000 |---------| TMM41464-10 |
| |---------| |--------------| | 315-5295| TMM41464-10 |
| | 315-5296| |HITACHI FD1094| |(QFP100) | TMM41464-10 |
|-| |(QFP100) | |317-0xxx-0xx | | | TMM41464-10 |
| | | |--------------| |---------| TMM41464-10 |
|-| |---------| TMM41464-10 |
| TMM41464-10 |
| |---------| TMM41464-10 |
|S |---------| | 315-5295| TMM41464-10 |
|E 20MHz | 315-5295| |(QFP100) | TMM41464-10 |
|G |(QFP100) | | | TMM41464-10 |
|A | | |---------| TMM41464-10 |
| |---------| TMM41464-10 |
|5 |---------| |
|6 |---------| |---------| | 315-5293| |
| | 315-5294| | 315-5292| | (QFP160)| |
| |(QFP100) | | (QFP160)| 32MHz | | |
| MB81C78A-45 | | | | |---------| |
|-| MB81C78A-45 |---------| |---------|M5M4464-12 x4 MB81461-12 x6 |
| |
|-| YM3012 (*) |
| |--------| |
| |315-5242| HM65256 HM65256 HM65256 M5M4464-12 x4 MB81461-12 x6 |
| |(QFP44) | HM65256 HM65256 HM65256 |
|------------|--------|---------------------------------------------------------|
(*) Unpopulated Sockets for MB81C4256 x4
(3rd Revision)
837-6442-02 SYSTEM 24 (C) SEGA 1987
|-------------------------------------------------------------------------------|
| YM2151 DSW1 EPRxxxxx.IC1 --------------------------| TC514256-10 |
| DSW2 EPRxxxxx.IC2 |-------------------------- TC514256-10 |
| CN2 TC514256-10 |
| 68000 |---------| TC514256-10 |
| |---------| |--------------| | 315-5295| TC514256-10 |
| | 315-5296| |HITACHI FD1094| |(QFP100) | TC514256-10 |
|-| |(QFP100) | |317-0xxx-0xx | | | TC514256-10 |
| | | |--------------| |---------| TC514256-10 |
|-| |---------| |
| |
| |---------| |
|S |---------| | 315-5295| |
|E 20MHz | 315-5295| |(QFP100) | |
|G |(QFP100) | | | |
|A | | |---------| |
| |---------| |
|5 |---------| |
|6 |---------| |---------| | 315-5293| |
| | 315-5294| | 315-5292| | (QFP160)| |
| |(QFP100) | | (QFP160)| 32MHz | | |
| MB81C78A-45 | | | | |---------| |
|-| MB81C78A-45 |---------| |---------| MB81461-12 x6 |
| |
|-| YM3012 |
| |--------| |
| |315-5242| HM65256 HM65256 TC51832 TC514256-10 x4 MB81461-12 x6 |
| |(QFP44) | HM65256 HM65256 TC51832 |
|------------|--------|---------------------------------------------------------|
Notes:
315-5292: Custom Sega IC (QFP160, Tilemap Generator)
315-5293: Custom Sega IC (QFP160, Object Generator)
315-5294: Custom Sega IC (QFP100, Mixer Chip)
315-5295: Custom Sega IC (QFP100, Object Generator)
315-5296: Custom Sega IC (QFP100, I/O Chip)
315-5242: Custom Sega IC (QFP44, Colour Encoder)
68000 clock: 10.000MHz
Hitachi FD1094 clock: 10.000MHz
YM2151 clock: 4.000MHz
VSync: 58Hz
HSync: 24.33kHz (All System24 games require 24kHz monitor)
CN2 (Above PCB): Connector for ROM Board (Not used for floppy-based games)
CN2 (Below PCB): Connector for Floppy Controller Board (Not used for ROM-based games)
Main PCB Pinout same as System 16
Floppy Drive is a standard 1.44 High Density drive, but the controller is custom and
the floppy disk format is custom. The floppy disk can be read with "Anadisk"
depending on the PC being used and it's floppy controller. Most clone PC's can't read the
System 24 floppies even with "Anadisk"[1]. But many brand-name PC's can. It's likely due to the
proprietary nature of the components used in brand-name PC's. Generally the older and crappier
the PC is, the better chance you have of being able to read the floppy ;-)
[1] Actually, most can _except_ for the Hotrod disks. Those 8K sectors are deadly.
Floppy Controller PCB Layout
----------------------------
837-6443 ___________
|---------------| DATA |-- ||||---|
| PWR |
| 74LS367 74LS05 |
| 74LS367 74LS174 |
| MB4107 74LS05 |
| |
| MB89311 74LS139 8MHz |
| CN1 |
| --------------------------| |
| |-------------------------- |
|--------------------------------------|
I/O Controller PCB Layout
-------------------------
834-6510
(sticker 834-6510-01) ___________
|----------------------| IDC 34 |---|
| |
| |
| D4701 |
| MSM6253RS |
| |
| D4701 MSM6253RS 74LS139 |
| |
| CN1 |
| --------------------------| |
| |-------------------------- |
|--------------------------------------|
Notes:
- For games other than Hot Rod, ICs other than LS139 and one uPD4701A are not
populated. Hot Rod doesn't seem to use the second MSM6253 (whose four inputs
are labeled "BLAKE" on the schematics), but has it populated anyway.
- CN1 is shown for completeness, it's actually underneath the I/O PCB.
- The custom I/O board plugs into the top connector on the main board and
is used for player steering controls. The wiring diagram has 8 pins coming from
the connector. Four are labelled 'JST4P 1P (L)', the other four are labelled
'JST4P 2P (R)'. I assume this is for an analog wheel or similar for player 1
(being on the left) and player 2 (being on the right)
The wiring diagram also lists some buttons for both PL1 and PL2 coming from
the regular 56-way edge connector.... 'Nitro' and 'Accel'
The manual shows a controller that looks like a spinner which they call
a 'sensor board' with part 839-0138 and has a photo-sensor disc, which looks
like it's used for steering.
This board is used on Hot Rod, Rough Racer and the Golf games only.
ROM Board Layout
----------------
837-7187-01
171-5875-01B
(SYSTEM24) (C)SEGA 1989 . 1991
|------------------------------------------|
| |
| |
| J1 |
|CN1 ROM1.IC4 ROM2.IC5 J2 |
||-| J3 |
|| | J4 |
|| | ROM3.IC6 ROM4.IC7 |
|| | J5 |
|| | J6 |
|| | ROM5.IC8 ROM6.IC9 J7 |
|| | J8 |
|| | J9 |
|| | ROM7.IC10 ROM8.IC11 |
|| | |
|| | 74HC4040 74LS139 |
||-| EPM5032DC.IC2 |
|------------------------------------------|
Notes:
CN1: Connector for joining ROM board to Main Board. This connector is above and below the PCB to allow for chaining of several boards.
The ROM Daughter board has a protection device on it at location IC2. It's an Erasable Programmable Logic Device; EPLD, like a normal PLD,
but uses an EPROM and is erasable and re-programmable. It's type is Altera EPM5032DC. It's part of the Altera MAX 5000 Programmable Logic
Device Family and (generally) has it's protection bit set at the factory.
All jumpers are 2 pins, they're either shorted or not shorted. All ROMs are configured as the same type.
See the table below for details.
Jumpers to set ROM sizes:
2M (J1, J3, J6, J8)
4M (J2, J3, J7, J9)
8M (J2, J4, J5, J9)
FD1094/Floppy/ROM details
-------------------------
Game FD1094 Floppy ROMs Other
-------------------------------------------------------------------------------------------------------------------------------------------------------------
Hot Rod (3p Turbo) none DS3-5000-01D Main Board: EPR11338.IC1, EPR11339.IC2 I/O Controller PCB, Floppy Controller PCB
Hot Rod (4p Rev C) none DS3-5000-01A Main Board: EPR11338.IC1, EPR11339.IC2 I/O Controller PCB, Floppy Controller PCB
Rev C
Hot Rod (4p Japanese none DS3-5000-01A Main Board: EPR11338.IC1, EPR11339.IC2 I/O Controller PCB, Floppy Controller PCB
Rev B) Rev B
Scramble Spirits none DS3-5000-02? Main Board: EPR12186.IC1, EPR12187.IC2 Floppy Controller PCB
Scramble Spirits 317-0058-02D DS3-5000-02D Main Board: EPR12186.IC1, EPR12187.IC2 Floppy Controller PCB
(Encrypted Version)
Gain Ground (Japan) 317-0058-03B DS3-5000-03B Main Board: EPR12186.IC1, EPR12187.IC2 Floppy Controller PCB
Gain Ground 317-0058-03D DS3-5000-03D Main Board: EPR12186.IC1, EPR12187.IC2 Floppy Controller PCB
Crack Down (Japan) 317-0058-04B DS3-5000-04B Main Board: EPR12186.IC1, EPR12187.IC2 Floppy Controller PCB
Rev A
Crack Down 317-0058-04D DS3-5000-04D Main Board: EPR12186.IC1, EPR12187.IC2 Floppy Controller PCB
Super Masters Golf 317-0058-05B DS3-5000-05B Main Board: EPR12186.IC1, EPR12187.IC2 I/O Controller PCB, Floppy Controller PCB
Rev B
Super Masters Golf 317-0058-05D DS3-5000-05D Main Board: EPR12186.IC1, EPR12187.IC2 I/O Controller PCB, Floppy Controller PCB
Rev D
Rough Racer 317-0058-06B DS3-5000-06B Main Board: EPR12186.IC1, EPR12187.IC2 I/O Controller PCB, Floppy Controller PCB
Bonanza Bros none DS3-5000-07D Main Board: EPR12186.IC1, EPR12187.IC2 Floppy Controller PCB
Daughter Board: MPR13187.IC4, MPR13188.IC5, MPR13189.IC6
MPR13190.IC7
EPLD: 317-0156
Quiz Syukudai wo 317-0058-08B DS3-5000-08B Main Board: EPR12186.IC1, EPR12187.IC2 Floppy Controller PCB
Wasuremashita
Dynamic Country Club 317-0058-09D DS3-5000-09D Main Board: EPR13947.IC1, EPR13948.IC2 I/O Controller PCB, Floppy Controller PCB
(Disk version)
Dynamic Country Club none none Main Board: EPR13947.IC1, EPR13948.IC2
(ROM version) Daughter Board: EPR15345.IC4 EPR15344.IC5, MPR14097.IC6
MPR14096.IC7
EPLD: 317-0177
Quiz Mekuromeku Story none none Main Board: EPR15342.IC1, EPR15343.IC2
Daughter Board: EPR15344.IC4, EPR15345.IC5, EPR15346.IC6
EPR15347.IC7, EPR15348.IC8, EPR15349.IC9
EPLD: 317-0205
Tokoro San no none none Main Board: EPR14812.IC1, EPR14813.IC2
MahMahjan Daughter Board: MPR14819.IC4, MPR14820.IC5, MPR14821.IC6
MPR14822IC.7, MPR14823.IC8, MPR14824.IC9
MPR14825.IC10, MPR14826.IC11
EPLD: 317-0200
Quiz Rouka Ni none none Main Board: EPR14484.IC1, EPR14485.IC2
Tattenasai Daughter Board: EPR14482.IC5, EPR14483.IC7
EPLD: 317-0191
Tokoro San no none none Main Board: EPR16798.IC1, EPR16799.IC2
MahMahjan 2 Daughter Board: MPR16800.IC4, MPR16801.IC5, MPR16802.IC6
MPR16803.IC7, MPR16804.IC8, MPR16805.IC9
MPR16806.IC10, MPR16807.IC11
EPLD: 317-0220
Quiz Ghost Hunter none none Main Board: EPR16899B.IC1, EPR16900B.IC2
Daughter Board: MPR16901A.IC4, MPR16902A.IC5, MPR16903.IC6
MPR16904.IC7, MPR16905.IC8, MPR16906.IC9
MPR16907.IC10, MPR16908.IC11
EPLD: 317-0226
Notes:
A regular 68000-10 is used in position IC3. If used, the Hitachi CPU sits at position IC4.
Where FD1094 is listed as 'none', a standard 68000 CPU is used instead at IC4 on the PCB.
The last 3 digits of the floppy number is also the last part of the Hitachi CPU number....they're a matching pair.
So if one had the Hitachi part number and a floppy without a label, it's possible to create the correct floppy disk name from
the last 3 digits of the Hitachi FD1094 part number.
*/
/* system24temp_ functions / variables are from shared rewrite files,
once the rest of the rewrite is complete they can be removed, I
just made a copy & renamed them for now to avoid any conflicts
*/
#include "emu.h"
#include "segas24.h"
#include "segaipt.h"
#include "cpu/m68000/m68000.h"
#include "fd1094.h"
#include "machine/msm6253.h"
#include "machine/nvram.h"
#include "machine/upd4701.h"
#include "315_5296.h"
#include "sound/dac.h"
#include "sound/ymopm.h"
#include "segaic24.h"
#include "speaker.h"
#define MASTER_CLOCK XTAL(20'000'000)
#define VIDEO_CLOCK XTAL(32'000'000)
#define TIMER_CLOCK (VIDEO_CLOCK/4)
#define HSYNC_CLOCK (VIDEO_CLOCK/2/656.0)
/* TODO: understand why divisors don't match at all with the reference */
#define FRC_CLOCK_MODE0 (MASTER_CLOCK/2)/24 // /16 according to Charles
#define FRC_CLOCK_MODE1 (MASTER_CLOCK/2)/1536 // /1024 according to Charles, but /1536 sounds better
#define FDC_LEGACY_LOG 0
#define FDC_LOG(x) do { if (FDC_LEGACY_LOG) logerror x; } while (0)
enum {
IRQ_YM2151 = 1,
IRQ_TIMER = 2,
IRQ_VBLANK = 3,
IRQ_SPRITE = 4,
IRQ_FRC = 5
};
// Floppy Disk Controller
void segas24_state::fdc_init()
{
m_fdc_track_side = 0;
m_fdc_mode = 0;
m_fdc_status = 0;
m_fdc_track = 0;
m_fdc_sector = 0;
m_fdc_data = 0;
m_fdc_phys_track = 0;
m_fdc_irq = false;
m_fdc_drq = false;
m_fdc_index_count = 0;
}
void segas24_state::device_post_load()
{
switch(m_fdc_mode) {
case 0x9:
case 0xb:
m_fdc_pt = &m_floppy[m_track_size*(2*m_fdc_phys_track+m_fdc_track_side) + (m_track_size - m_fdc_span)];
break;
default:
break;
}
}
uint16_t segas24_state::fdc_r(offs_t offset)
{
if(!m_track_size)
return 0xffff;
switch(offset) {
case 0:
m_fdc_irq = false;
return m_fdc_status;
case 1:
return m_fdc_track;
case 2:
return m_fdc_sector;
case 3:
default: {
int res = m_fdc_data;
if(m_fdc_drq) {
m_fdc_span--;
// FDC_LOG(("Read %02x (%d)\n", res, m_fdc_span));
if(m_fdc_span) {
m_fdc_pt++;
m_fdc_data = *m_fdc_pt;
} else {
FDC_LOG(("FDC: transfert complete\n"));
m_fdc_drq = false;
m_fdc_status = 0;
m_fdc_irq = true;
}
} else
FDC_LOG(("FDC: data read with drq down\n"));
return res;
}
}
}
void segas24_state::fdc_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
if(!m_track_size)
return;
if(ACCESSING_BITS_0_7) {
data &= 0xff;
switch(offset) {
case 0:
m_fdc_irq = false;
switch(data >> 4) {
case 0x0:
FDC_LOG(("FDC: Restore\n"));
m_fdc_phys_track = m_fdc_track = 0;
m_fdc_irq = true;
m_fdc_status = 4;
break;
case 0x1:
FDC_LOG(("FDC: Seek %d\n", m_fdc_data));
m_fdc_phys_track = m_fdc_track = m_fdc_data;
m_fdc_irq = true;
m_fdc_status = m_fdc_track ? 0 : 4;
break;
case 0x9:
m_fdc_track_side = (data & 8 ? 1 : 0);
m_fdc_mode = 0x9;
FDC_LOG(("Read multiple [%02x] %d..%d side %d track %d\n", data, m_fdc_sector, m_fdc_sector+m_fdc_data-1, m_fdc_track_side, m_fdc_phys_track));
m_fdc_pt = &m_floppy[m_track_size*(2*m_fdc_phys_track+m_fdc_track_side)];
m_fdc_span = m_track_size;
m_fdc_status = 3;
m_fdc_drq = true;
m_fdc_data = *m_fdc_pt;
break;
case 0xb:
m_fdc_track_side = (data & 8 ? 1 : 0);
m_fdc_mode = 0xb;
FDC_LOG(("Write multiple [%02x] %d..%d side %d track %d\n", data, m_fdc_sector, m_fdc_sector+m_fdc_data-1, m_fdc_track_side, m_fdc_phys_track));
m_fdc_pt = &m_floppy[m_track_size*(2*m_fdc_phys_track+m_fdc_track_side)];
m_fdc_span = m_track_size;
m_fdc_status = 3;
m_fdc_drq = true;
break;
case 0xd:
m_fdc_mode = 0xd;
FDC_LOG(("FDC: Forced interrupt\n"));
m_fdc_span = 0;
m_fdc_drq = false;
m_fdc_irq = BIT(data, 0);
m_fdc_status = 0;
break;
case 0xf:
if(data == 0xfe)
FDC_LOG(("FDC: Assign mode %02x\n", m_fdc_data));
else if(data == 0xfd)
FDC_LOG(("FDC: Assign parameter %02x\n", m_fdc_data));
else
FDC_LOG(("FDC: Unknown command %02x\n", data));
break;
default:
FDC_LOG(("FDC: Unknown command %02x\n", data));
break;
}
break;
case 1:
FDC_LOG(("FDC: Track register %02x\n", data));
m_fdc_track = data;
break;
case 2:
FDC_LOG(("FDC: Sector register %02x\n", data));
m_fdc_sector = data;
break;
case 3:
if(m_fdc_drq) {
// FDC_LOG("Write %02x (%d)\n", data, m_fdc_span);
*m_fdc_pt++ = data;
m_fdc_span--;
if(!m_fdc_span) {
FDC_LOG(("FDC: transfert complete\n"));
m_fdc_drq = false;
m_fdc_status = 0;
m_fdc_irq = true;
}
} else
FDC_LOG(("FDC: Data register %02x\n", data));
m_fdc_data = data;
break;
}
}
}
uint16_t segas24_state::fdc_status_r()
{
if(!m_track_size)
return 0xffff;
return 0x90 | (m_fdc_irq ? 2 : 0) | (m_fdc_drq ? 1 : 0) | (m_fdc_phys_track ? 0x40 : 0) | (m_fdc_index_count ? 0x20 : 0);
}
void segas24_state::fdc_ctrl_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
if(ACCESSING_BITS_0_7)
FDC_LOG(("FDC control %02x\n", data & 0xff));
}
// I/O Mappers
uint8_t segas24_state::dcclub_p1_r()
{
static const uint8_t pos[16] = { 0, 1, 3, 2, 6, 4, 12, 8, 9, 0, 0, 0 };
return (m_p1->read() & 0xf) | ((~pos[m_paddle->read()>>4]<<4) & 0xf0);
}
uint8_t segas24_state::dcclub_p3_r()
{
static const uint8_t pos[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 2 };
return(~pos[m_paddle->read()>>4] & 0x03) | 0xfc;
}
uint8_t segas24_state::mahmajn_input_line_r()
{
return ~(1 << m_cur_input_line);
}
uint8_t segas24_state::mahmajn_inputs_r()
{
return m_mj_inputs[m_cur_input_line].read_safe(0xff);
}
void segas24_state::mahmajn_mux_w(uint8_t data)
{
if(data & 4)
m_cur_input_line = (m_cur_input_line + 1) & 7;
}
void segas24_state::hotrod_lamps_w(uint8_t data)
{
// Lamps
}
uint16_t segas24_state::iod_r(offs_t offset)
{
logerror("IO daughterboard read %02x %s\n", offset, machine().describe_context());
return 0xffff;
}
void segas24_state::iod_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
logerror("IO daughterboard write %02x, %04x & %04x %s\n", offset, data, mem_mask, machine().describe_context());
}
/* HACK for Gain Ground to avoid 'forced free play' issue
Notes from Olivier
The encrypted CPU does:
849c: moveq #-1, d1
849e: move.w 0xa00000, d0
84a4: cmp.w 0xa00000, d0
84aa: beq.s 84a4
84ac: add.w #0x200, d0
84b0: andi.w #0xfff, d0
84b4: cmp.w 0xa00000, d0 // 16 cycles
84ba: dbeq d1, 84b4 // 10 cycles
84be: addi.w #0x1b5f, d1
84c2: bpl 84c8
84c4: st 0x404 // Force freeplay
84c8: ...
a00000 is the timer 12bit counter. It is configured to be clocked by
the hsync pulse. That code counts how many loops it takes for the
counter to count 512 times. The force freeplay happens if the count
is more than 7007.
Pixel clock is 16MHz, hsync is every 656 pixels, cpu clock is 10MHz.
So that's 656*10/16=410 cpu clocks per hsync, or 410*512=209902 total.
With 26 cycles per loop, that's 8073 loops. Freeplay it is.
--- Update from Charles MacDonald ---
I ran some tests. For the two CPUs, A (68000) and B (FD1094), normally
there are no wait states when CPU A accesses $A00000. As that address
is on CPU A's bus, CPU B's accesses to it take twice as long (eight 10 MHz
clocks instead of four) due to contention. The only exception is when
CPU A is completely idle from a STOP instruction, at which point CPU B
can access that memory at full speed (four clocks per access).
Assuming Gain Ground has CPU A running code out of BIOS ROM or work RAM,
and CPU B is running out of work RAM, then each one of those $A00000
accesses will eat up double the time.
The other factor is DRAM refresh for the work RAM, both CPUs have some
memory access stretched out by four cycles every 19 to 20 ms. It looks
like both DRAM banks are refreshed in parallel which seems to explain
why refresh on CPU A's bus doesn't count as contention for CPU B and
vice-versa. So there's only refresh event that eats up time for both
CPUs to worry about.
*/
TIMER_CALLBACK_MEMBER(segas24_state::gground_hack_timer_callback)
{
m_subcpu->set_clock_scale(1.0f);
}
// Cpu #1 reset control
void segas24_state::cnt1(int state)
{
if (bool(state) != m_cnt1)
{
if (state)
{
m_subcpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
m_subcpu->pulse_input_line(INPUT_LINE_RESET, attotime::zero);
//osd_printf_debug("enable 2nd cpu!\n");
//machine().debug_break();
if (m_gground_hack_timer)
{
m_subcpu->set_clock_scale(0.7f); // reduce clock speed temporarily so a check passes, see notes above
m_gground_hack_timer->adjust(attotime::from_seconds(2));
}
}
else
m_subcpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
}
m_cnt1 = bool(state);
}
// Rom board bank access
void segas24_state::reset_bank()
{
if (m_romboard != nullptr)
{
m_rombank[0]->set_entry(m_curbank & 15);
m_rombank[1]->set_entry(m_curbank & 15);
}
}
uint8_t segas24_state::curbank_r()
{
return m_curbank;
}
void segas24_state::curbank_w(uint8_t data)
{
m_curbank = data;
reset_bank();
}
uint8_t segas24_state::frc_mode_r()
{
return m_frc_mode & 1;
}
void segas24_state::frc_mode_w(uint8_t data)
{
/* reset frc if a write happens here */
m_frc_cnt_timer->reset();
m_frc_mode = data & 1;
}
uint8_t segas24_state::frc_r()
{
int32_t result = (m_frc_cnt_timer->elapsed() * (m_frc_mode ? FRC_CLOCK_MODE1 : FRC_CLOCK_MODE0).dvalue()).as_double();
result %= ((m_frc_mode) ? 0x67 : 0x100);
return result;
}
void segas24_state::frc_w(uint8_t data)
{
/* Undocumented behaviour, Bonanza Bros. seems to use this for irq ack'ing ... */
m_maincpu->set_input_line(IRQ_FRC+1, CLEAR_LINE);
m_subcpu->set_input_line(IRQ_FRC+1, CLEAR_LINE);
}
// Protection magic latch
const uint8_t segas24_state::s_mahmajn_mlt[8] = { 5, 1, 6, 2, 3, 7, 4, 0 };
const uint8_t segas24_state::s_mahmajn2_mlt[8] = { 6, 0, 5, 3, 1, 4, 2, 7 };
const uint8_t segas24_state::s_qgh_mlt[8] = { 3, 7, 4, 0, 2, 6, 5, 1 };
const uint8_t segas24_state::s_bnzabros_mlt[8] = { 2, 4, 0, 5, 7, 3, 1, 6 };
const uint8_t segas24_state::s_qrouka_mlt[8] = { 1, 6, 4, 7, 0, 5, 3, 2 };
const uint8_t segas24_state::s_quizmeku_mlt[8] = { 0, 3, 2, 4, 6, 1, 7, 5 };
const uint8_t segas24_state::s_dcclub_mlt[8] = { 4, 7, 3, 0, 2, 6, 5, 1 };
uint8_t segas24_state::mlatch_r()
{
return m_mlatch;
}
void segas24_state::mlatch_w(uint8_t data)
{
int i;
uint8_t mxor = 0;
if(!m_mlatch_table) {
logerror("Protection: magic latch accessed but no table loaded %s\n", machine().describe_context());
return;
}
if(data != 0xff) {
for(i=0; i<8; i++)
if(m_mlatch & (1<<i))
mxor |= 1 << m_mlatch_table[i];
m_mlatch = data ^ mxor;
logerror("Magic latching %02x ^ %02x as %02x %s\n", data & 0xff, mxor, m_mlatch, machine().describe_context());
} else {
logerror("Magic latch reset %s\n", machine().describe_context());
m_mlatch = 0x00;
}
}
// Timers and IRQs
void segas24_state::irq_timer_sync()
{
attotime ctime = machine().time();
switch(m_irq_tmode) {
case 0:
break;
case 1: {
// Don't remove the floor(), the value may be slightly negative
int ppos = floor((m_irq_synctime - m_irq_vsynctime).as_double() * HSYNC_CLOCK.dvalue());
int cpos = floor((ctime - m_irq_vsynctime).as_double() * HSYNC_CLOCK.dvalue());
m_irq_tval += cpos-ppos;
break;
}
case 2: {
fatalerror("segas24_state::irq_timer_sync - case 2\n");
}
case 3: {
int ppos = floor((m_irq_synctime - m_irq_vsynctime).as_double() * TIMER_CLOCK.dvalue());
int cpos = floor((ctime - m_irq_vsynctime).as_double() * TIMER_CLOCK.dvalue());
m_irq_tval += cpos-ppos;
break;
}
}
m_irq_synctime = ctime;
}
void segas24_state::irq_timer_start(int old_tmode)
{
switch(m_irq_tmode) {
case 0:
if(old_tmode) {
m_irq_tval++;
if(m_irq_tval == 0x1000)
m_irq_timer->adjust(attotime::zero);
else
m_irq_timer->enable(false);
}
break;
case 1: {
int count = 0x1000 - m_irq_tval;
m_irq_timer->adjust(attotime::from_hz(HSYNC_CLOCK)*count);
break;
}
case 2:
fatalerror("segas24_state::irq_timer_start - case 2\n");
case 3: {
int count = 0x1000 - m_irq_tval;
m_irq_timer->adjust(attotime::from_hz(TIMER_CLOCK)*count);
break;
}
}
}
TIMER_DEVICE_CALLBACK_MEMBER(segas24_state::irq_timer_cb)
{
irq_timer_sync();
if(m_irq_tval != 0x1000)
fprintf(stderr, "Error: timer desync %x != 1000\n", m_irq_tval);
m_irq_tval = m_irq_tdata;
irq_timer_start(m_irq_tmode);
m_irq_timer_pend0 = m_irq_timer_pend1 = true;
if(m_irq_allow0 & (1 << IRQ_TIMER))
m_maincpu->set_input_line(IRQ_TIMER+1, ASSERT_LINE);
if(m_irq_allow1 & (1 << IRQ_TIMER))
m_subcpu->set_input_line(IRQ_TIMER+1, ASSERT_LINE);
if (m_irq_tmode == 1 || m_irq_tmode == 2)
{
// m_screen->update_now();
m_screen->update_partial(m_screen->vpos());
}
}
TIMER_DEVICE_CALLBACK_MEMBER(segas24_state::irq_timer_clear_cb)
{
m_irq_sprite = m_irq_vblank = false;
m_maincpu->set_input_line(IRQ_VBLANK+1, CLEAR_LINE);
m_maincpu->set_input_line(IRQ_SPRITE+1, CLEAR_LINE);
m_subcpu->set_input_line(IRQ_VBLANK+1, CLEAR_LINE);
m_subcpu->set_input_line(IRQ_SPRITE+1, CLEAR_LINE);
}
TIMER_DEVICE_CALLBACK_MEMBER(segas24_state::irq_frc_cb)
{
if(m_irq_allow0 & (1 << IRQ_FRC) && m_frc_mode == 1)
m_maincpu->set_input_line(IRQ_FRC+1, ASSERT_LINE);
if(m_irq_allow1 & (1 << IRQ_FRC) && m_frc_mode == 1)
m_subcpu->set_input_line(IRQ_FRC+1, ASSERT_LINE);
}
void segas24_state::irq_init()
{
m_irq_tdata = 0;
m_irq_tmode = 0;
m_irq_allow0 = 0;
m_irq_allow1 = 0;
m_irq_timer_pend0 = false;
m_irq_timer_pend1 = false;
m_irq_vblank = false;
m_irq_sprite = false;
m_irq_tval = 0;
m_irq_synctime = attotime::zero;
m_irq_vsynctime = attotime::zero;
}
void segas24_state::irq_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
switch(offset) {
case 0: {
irq_timer_sync();
COMBINE_DATA(&m_irq_tdata);
m_irq_tdata &= 0xfff;
irq_timer_start(m_irq_tmode);
break;
}
case 1:
if(ACCESSING_BITS_0_7) {
uint8_t old_tmode = m_irq_tmode;
irq_timer_sync();
m_irq_tmode = data & 3;
irq_timer_start(old_tmode);
}
break;
case 2:
m_irq_allow0 = data & 0x3f;
m_irq_timer_pend0 = false;
m_maincpu->set_input_line(IRQ_TIMER+1, CLEAR_LINE);
m_maincpu->set_input_line(IRQ_YM2151+1, m_irq_yms && (m_irq_allow0 & (1 << IRQ_YM2151)) ? ASSERT_LINE : CLEAR_LINE);
m_maincpu->set_input_line(IRQ_VBLANK+1, m_irq_vblank && (m_irq_allow0 & (1 << IRQ_VBLANK)) ? ASSERT_LINE : CLEAR_LINE);
m_maincpu->set_input_line(IRQ_SPRITE+1, m_irq_sprite && (m_irq_allow0 & (1 << IRQ_SPRITE)) ? ASSERT_LINE : CLEAR_LINE);
//m_maincpu->set_input_line(IRQ_FRC+1, m_irq_frc && (m_irq_allow0 & (1 << IRQ_FRC)) ? ASSERT_LINE : CLEAR_LINE);
break;
case 3:
m_irq_allow1 = data & 0x3f;
m_irq_timer_pend1 = false;
m_subcpu->set_input_line(IRQ_TIMER+1, CLEAR_LINE);
m_subcpu->set_input_line(IRQ_YM2151+1, m_irq_yms && (m_irq_allow1 & (1 << IRQ_YM2151)) ? ASSERT_LINE : CLEAR_LINE);
m_subcpu->set_input_line(IRQ_VBLANK+1, m_irq_vblank && (m_irq_allow1 & (1 << IRQ_VBLANK)) ? ASSERT_LINE : CLEAR_LINE);
m_subcpu->set_input_line(IRQ_SPRITE+1, m_irq_sprite && (m_irq_allow1 & (1 << IRQ_SPRITE)) ? ASSERT_LINE : CLEAR_LINE);
//m_subcpu->set_input_line(IRQ_FRC+1, m_irq_frc && (m_irq_allow1 & (1 << IRQ_FRC)) ? ASSERT_LINE : CLEAR_LINE);
break;
}
}
// gground bp at 849c (84a4)
// cmp.w $a00000, d0 | 16
// dbeq d1, 84b4 | 10
// 26 cycles/tour
// 0x200 counts
// 656 cycles/ligne
// 656*0x200/26 = 12918 (3276) -> cd89 (got e087, delta = 1f78, 8056)
// 410 cycles/ligne
// 410*0x200/26 = 8073
uint16_t segas24_state::irq_r(offs_t offset)
{
switch(offset) {
case 2:
m_irq_timer_pend0 = false;
m_maincpu->set_input_line(IRQ_TIMER+1, CLEAR_LINE);
break;
case 3:
m_irq_timer_pend1 = false;
m_subcpu->set_input_line(IRQ_TIMER+1, CLEAR_LINE);
break;
}
irq_timer_sync();
return m_irq_tval & 0xfff;
}
TIMER_DEVICE_CALLBACK_MEMBER(segas24_state::irq_vbl)
{
int irq, mask;
int scanline = param;
/* TODO: perhaps vblank irq happens at 400, sprite IRQ certainly don't at 0! */
if(scanline == 0) { irq = IRQ_SPRITE; m_irq_sprite = true; }
else if(scanline == 384) { irq = IRQ_VBLANK; m_irq_vblank = true; }
else
return;
m_irq_timer_clear->adjust(attotime::from_hz(HSYNC_CLOCK));
mask = 1 << irq;
if(m_irq_allow0 & mask)
m_maincpu->set_input_line(1+irq, ASSERT_LINE);
if(m_irq_allow1 & mask)
m_subcpu->set_input_line(1+irq, ASSERT_LINE);
if(scanline == 384) {
// Ensure one index pulse every 20 frames
// The is some code in bnzabros at 0x852 that makes it crash
// if the pulse train is too fast
m_fdc_index_count++;
if(m_fdc_index_count >= 20)
m_fdc_index_count = 0;
}
irq_timer_sync();
m_irq_vsynctime = machine().time();
}
void segas24_state::irq_ym(int state)
{
m_irq_yms = state;
m_maincpu->set_input_line(IRQ_YM2151+1, m_irq_yms && (m_irq_allow0 & (1 << IRQ_YM2151)) ? ASSERT_LINE : CLEAR_LINE);
m_subcpu->set_input_line(IRQ_YM2151+1, m_irq_yms && (m_irq_allow1 & (1 << IRQ_YM2151)) ? ASSERT_LINE : CLEAR_LINE);
}
// 315-5242
uint16_t segas24_state::paletteram_r(offs_t offset)
{
return m_paletteram[offset];
}
void segas24_state::paletteram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
int r, g, b;
COMBINE_DATA (m_paletteram + offset);
data = m_paletteram[offset];
r = (data & 0x00f) << 4;
if(data & 0x1000)
r |= 8;