/
jaguar.cpp
2666 lines (2221 loc) · 117 KB
/
jaguar.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:Aaron Giles,Nathan Woods,Angelo Salese, Robbbert
/***************************************************************************
Atari Jaguar (Home) & Atari CoJag (Arcade) hardware
The CoJag arcade system is based on the Jaguar system, but with an upgraded
main CPU (68020 or MIPS instead of the plain 68000 found in the Jaguar)
driver by Aaron Giles
console support originally by Nathan Woods
CoJag Games supported:
* Area 51 (4 Sets)
* Maximum Force (3 Sets)
* Area 51/Maximum Force Duo (2 Sets)
* Vicious Circle
* Fishin' Frenzy
* Freeze
To do:
* (CoJag) map out unused RAM per-game via memory_nop_read/write
* (Jaguar) support is very poor, most games aren't properly playable
or have severe performance issues or crashes related to the unsafe
blitter code. Please refer to jaguar SW list file for more details.
* The code (GPU/DSP access) should probably be refactored around the
16-bit interface from the plain 68k, the driver currently uses
trampoline functions due to the original driver being entirely
32-bit due to the CPUs on CoJag.
Note: There is believed to be a 68020 version of Maximum Force
(not confirmed or dumped)
****************************************************************************
Area51/Maximum Force (c)1997 Atari Games
Maximum Force
A055451
Components:
sdt79r3041-20j
Atari Jaguar CPU V1.0 6sc880hf106
Atari Jaguar DSP V1.0 sc414201ft (has Motorolla logo)
Altera epm7128elc84-15 marked A-21652
VIA vt83c461 IDE controller
Actel a1010b marked A-22096 near IDE and gun inputs
Dallas ds1232s watchdog
52MHz osc near Altera PLCC
40MHz osc near 79R3041
14.318180MHz osc near Jag DSP
12x hm514260cj7 RAM (near Jaguar CPU/DSP)
4x sdt71256 RAM (near Boot ROMs's)
Atmel atf16v8b marked a-21647 (near Jag CPU)
Altera ep22lc-10 marked A-21648 (near Jag DSP)
ICT 22cv10aj marked A-21649 (near Jag CPU)
ICT 22cv10aj marked A-21650 (near Jag CPU)
ICT 22cv10aj marked A-21651 (near Jag CPU)
tea6320t
AKM ak4310vm
tda1554q amplifier
Microchip 28c16a-15 BRAM
ROM's:
27c4001
R3K MAX/A51 KIT
LL
(c)1997 Atari
V 1.0
27c4001
R3K MAX/A51 KIT
LH
(c)1997 Atari
V 1.0
27c4001
R3K MAX/A51 KIT
HL
(c)1997 Atari
V 1.0
27c4001
R3K MAX/A51 KIT
HH
(c)1997 Atari
V 1.0
Jumpers:
jsp1 (1/2 connected= w/sub 2/3 connected= normal speaker)
jsp2 (1/2 connected= w/sub 2/3 connected= normal speaker)
jamaud (1/2 connected=stereo 2/3 connected=mono)
jimpr (1/2 connected=hi video R impedance 2/3 connected=lo)
jimpg (1/2 connected=hi video G impedance 2/3 connected=lo)
jimpb (1/2 connected=hi video B impedance 2/3 connected=lo)
Connectors:
idea standard IDE connector
ideb laptop size IDE connector
jgun1 8 pin gun input
jgun2 8 pin gun input
xtracoin 1 6 pin (coin3/4 bills?)
jvupdn 3 pin (?)
jsync 3 pin (?)
JAMMA
jspkr left/right/subwoofer output
hdpower 4 pin PC power connector for HD
****************************************************************************
Area 51 (Time Warner Interactive License)
Atari/Mesa Logic, 1995
This game runs on Atari Cojag 68k hardware.
PCB Layouts
-----------
Main Board:
COJAG A053538
ATARI GAMES (C) 1994
(Atari comment near AMP - 'MMM, DONUTS.')
|--------------------------------------------------|
|TDA1554Q TEA6320T AK4310 JXCLKTRM |
|JSPKR ST91D314 XC7336 |
| JSP1 JWELLSR PAL4 PAL5 |
| JSP4 JSP2 PAL1 45160 45160 * * |
| HDPOWER JSP3 JWELLSB JXBUS|
| SELFTEST PAL2 PAL6 45160 45160 * * |
| LED JWELLSG |
| LED |------|45160 45160 * * |
|J LED |JAGUAR| |
|A | CPU |45160 45160 * * |
|M | | |
|M |------| |
|A |
| 14.31818MHz |------| |
| LM613 |JAGUAR| |
| 52MHz PAL3 | DSP | |
| | | |
| JSYNC |------| |
| JVUPDN DIP8 |
| A1010B |
|JPLY3 JVCR VT83C461 |
| |
| LED |
| JPLY4 JGUN2 JGUN1 JIDEB |
|--------------------------------------------------|
Notes:
JAGUAR CPU - Atari Jaguar CPU (QFP208)
JAGUAR DSP - Atari Jaguar DSP (QFP160)
45160 - TMS45160DZ-70 512K x16 DRAM (SOJ40)
Note: This RAM is in banks. There are 4 banks, each bank is 2MBytes x 64bit
Only banks 0 and 1 are populated.
* - Unpopulated DRAM positions (banks 2 and 3)
TDA1554Q - Philips TDA1554Q power AMP
TEA6320T - Philips TEA6320T op AMP (SOP32)
AK4310 - AKM AK4310VM (SOIC24)
ST91D314 - STS Microelectronics ST91D314 3403 op AMP (SOIC14)
PAL1 - ATMEL ATF16V8B PAL (labelled '136105-0006', PLCC20)
PAL2 - ATMEL ATF16V8B PAL (labelled '136105-0006', PLCC20)
PAL3 - ATMEL ATF16V8B PAL (labelled '136105-0007', PLCC20)
PAL4, PAL5 - Philips PL22V10-10A PAL (labelled 'MYF 136105-0008', PLCC28)
PAL6 - ATMEL ATF16V8B (labelled '136105-0005', PLCC20)
A1010B - ACTEL A1010B Complex Programmable Logic Device (labeled 'MYF 136105-0010', PLCC44)
XC7336 - Xilinx XC7336 Complex PRogrammable Logic Device (labelled 'MYF 136105-0009', PLCC44)
VT83C461 - VIA VT83C461 IDE Hard Drive Controller (QFP100)
LM613 - (DIP16)
SELFTEST - Test Switch
HDPOWER - Standard (PC-type) 4 pin hard drive power connector
JSP1 - 3 pin jumper block, set to 2-3
JSP2 - 3 pin jumper block, set to 2-3
JSP3 - 3 pin jumper block, jumper not installed
JSP4 - 3 pin jumper block, set to 2-3
JWELLSR - 3 pin jumper block, set to 2-3
JWELLSB - 3 pin jumper block, set to 2-3
JWELLSG - 3 pin jumper block, set to 2-3
JSYNC - 3 pin jumper block, jumper not installed
JVUPDN - 3 pin jumper block, jumper not installed
JVCR - 3 pin jumper block, jumper not installed
JXCLKTRM - 2 pin header, not shorted
JPLY3 - Connector for player 3 controls
JPLY4 - Connector for player 4 controls
JGUN1 - Connector for player 1 gun
JGUN2 - Connector for player 2 gun
JIDEB - Connector for 40 pin IDE cable connected to Quantum Fireball 1080AT IDE hard drive (C/H/S = 2112/16/63)
JSPKR - Connector for left/right speaker for stereo sound output
DIP8 - Unpopulated DIP8 socket
JXBUS - 96 pin connector to top board
Top Board:
EC20X32
A053448
ATARI GAMES (C) 1994
|------------------------------|
| 136105-0002C.3P|
| 71256 |
| 136105-0001C.3M|
| 71256 |
| 136105-0000C.3K|
| 71256 |
| 136105-0003C.3H|
| 71256 |
| LED |
| |
| AT28C16 DS1232 XC7354 |
| |
| |
| MC68EC020 |
| |
| 50MHz |
|------------------------------|
Notes:
MC68EC020 - Motorola 68EC020FG25 CPU clocked at 25MHz (QFP100)
AT28C16 - ATMEL 2k x8 EEPROM (DIP24)
XC7354 - Xilinx XC7354 Complex Programmable Logic Device (labelled 'MYF 136105-0004', PLCC68, socketed)
DS1232 - Dallas DS1232 System Reset IC (DIP8)
71256 - 32K x8 SRAM (SOJ28)
136105-0002C.3P - 27C040 EPROM (labelled 'AREA 51 136105-0002C (C)1995 ATARI GMS CS 55FE', DIP32)
136105-0001C.3M - 27C040 EPROM (labelled 'AREA 51 136105-0001C (C)1995 ATARI GMS CS 3DFD', DIP32)
136105-0000C.3K - 27C040 EPROM (labelled 'AREA 51 136105-0000C (C)1995 ATARI GMS CS 63FC', DIP32)
136105-0003C.3H - 27C040 EPROM (labelled 'AREA 51 136105-0003C (C)1995 ATARI GMS CS 45FF', DIP32)
****************************************************************************
Maximum Force
Atari, 1997
PCB Layout
----------
MAXIMUM FORCE A055451 ATARI GAMES (C) 1996
|-----------------------------------------------------------------------------------|
|HM514260CJ7 HM514260CJ7 HM514260CJ7 HM514260CJ7 AT28C16 |
| |
|HM514260CJ7 HM514260CJ7 HM514260CJ7 HM514260CJ7 PROGLL.17Y PROGLH.21Y |
| |
|HM514260CJ7 HM514260CJ7 HM514260CJ7 HM514260CJ7 PROGHL.21V PROGHH.21V |
| |
| |
| |------| |------| |
| |JAGUAR| |JAGUAR| |
|GAL GAL |GPU | |DSP | |----------| |
| |------| |------| | | |
| |IDT | |
|GAL GAL 40MHz |79R3041-20| |
| GAL | | |
| 14.31818MHz |----------| IDE |
|AK4310VM CONN |
| |-----------| |
|LM78L05 52MHz |ALTERA MAX | |
| |EPM7128ELC84 |
| TEA6320 | | |
|78L09 LM613 | | VIA |
| MONO/STEREO |-----------| VT83C461 |
|TDA1554 SELFTEST |
| DS1232 ACTEL_A1010B |
| HDD_PWR |
| JSPKR |--| JAMMA |--| JSYNC JVUPDN XTRACOIN1 JGUN1 JGUN2|
|-------| |----------------------------| |----------------------------------------|
Notes:
JGUN1 / JGUN2 - Connector for Guns
VIA VT83C461 - IDE Controller
JSPKR - Speaker Output Connector (for use with Stereo jumper)
****************************************************************************
Memory map (TBA)
========================================================================
MAIN CPU
========================================================================
------------------------------------------------------------
000000-3FFFFF R/W xxxxxxxx xxxxxxxx DRAM 0
400000-7FFFFF R/W xxxxxxxx xxxxxxxx DRAM 1
800000-BFFFFF R xxxxxxxx xxxxxxxx Graphic ROM bank
C00000-DFFFFF R xxxxxxxx xxxxxxxx Sound ROM bank
F00000-F000FF R/W xxxxxxxx xxxxxxxx Tom Internal Registers
F00400-F005FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table A
F00600-F007FF R/W xxxxxxxx xxxxxxxx CLUT - color lookup table B
F00800-F00D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer A
F01000-F0159F R/W xxxxxxxx xxxxxxxx LBUF - line buffer B
F01800-F01D9F R/W xxxxxxxx xxxxxxxx LBUF - line buffer currently selected
F02000-F021FF R/W xxxxxxxx xxxxxxxx GPU control registers
F02200-F022FF R/W xxxxxxxx xxxxxxxx Blitter registers
F03000-F03FFF R/W xxxxxxxx xxxxxxxx Local GPU RAM
F08800-F08D9F R/W xxxxxxxx xxxxxxxx LBUF - 32-bit access to line buffer A
F09000-F0959F R/W xxxxxxxx xxxxxxxx LBUF - 32-bit access to line buffer B
F09800-F09D9F R/W xxxxxxxx xxxxxxxx LBUF - 32-bit access to line buffer currently selected
F0B000-F0BFFF R/W xxxxxxxx xxxxxxxx 32-bit access to local GPU RAM
F10000-F13FFF R/W xxxxxxxx xxxxxxxx Jerry
F14000-F17FFF R/W xxxxxxxx xxxxxxxx Joysticks and GPIO0-5
F18000-F1AFFF R/W xxxxxxxx xxxxxxxx Jerry DSP
F1B000-F1CFFF R/W xxxxxxxx xxxxxxxx Local DSP RAM
F1D000-F1DFFF R xxxxxxxx xxxxxxxx Wavetable ROM
------------------------------------------------------------
Jaguar console schematics include a ADC0844 at U16, selected by GPIOL5. This IC
may or may not be populated.
Jaguar System Notes:
Protection Check
At power on, a checksum is performed on the cart to ensure it has been
certified by Atari. The actual checksum calculation is performed by the GPU,
the result being left in GPU RAM at address f03000. The GPU is instructed to
do the calculation when the bios sends a 1 to f02114 while it is in the
initialisation stage. The bios then loops, waiting for the GPU to finish the
calculation. When it does, it sets bit 15 of f02114 high. The bios then does
the compare of the checksum. The checksum algorithm is unknown, but the
final result must be 03d0dead. The bios checks for this particular result,
and if found, the cart is allowed to start. Otherwise, the background turns
red, and the console freezes.
Jaguar Logo
A real Jaguar will show the red Jaguar logo, the falling white Atari letters,
and the turning jaguar's head, accompanied by the sound of a flushing toilet.
The cart will then start. All Jaguar emulators (including this one) skip the
logo with the appropriate memory hack. The cart can also instruct the logo
be skipped by placing non-zero at location 800408. We do the same thing when
the cart is loaded (see the DEVICE_IMAGE_LOAD section below).
Start Address
The start address of a cart may be found at 800404. It is normally 802000.
***************************************************************************/
#include "emu.h"
#include "jaguar.h"
#include "bus/ata/hdd.h"
#include "bus/generic/carts.h"
#include "cpu/jaguar/jaguar.h"
#include "cpu/m68000/m68000.h"
#include "cpu/m68000/m68020.h"
#include "cpu/mips/mips1.h"
#include "imagedev/cdromimg.h"
#include "imagedev/snapquik.h"
#include "machine/eepromser.h"
#include "machine/vt83c461.h"
#include "machine/watchdog.h"
#include "sound/cdda.h"
#include "softlist_dev.h"
#include "speaker.h"
#include "cdrom.h"
#define COJAG_CLOCK XTAL(52'000'000)
#define R3000_CLOCK XTAL(40'000'000)
#define M68K_CLOCK XTAL(50'000'000)
/*************************************
*
* Local variables
*
*************************************/
/// HACK: Maximum force requests data but doesn't transfer it all before issuing another command.
/// According to the ATA specification this is not allowed, more investigation is required.
DECLARE_DEVICE_TYPE(COJAG_HARDDISK, cojag_hdd)
class cojag_hdd : public ide_hdd_device
{
public:
cojag_hdd(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: ide_hdd_device(mconfig, COJAG_HARDDISK, tag, owner, clock)
{
}
virtual void write_cs0(offs_t offset, uint16_t data, uint16_t mem_mask) override
{
// the first write is to the device head register
if( offset == 6 && (m_status & IDE_STATUS_DRQ))
{
m_status &= ~IDE_STATUS_DRQ;
}
ide_hdd_device::write_cs0(offset, data, mem_mask);
}
};
DEFINE_DEVICE_TYPE(COJAG_HARDDISK, cojag_hdd, "cojag_hdd", "HDD CoJag")
void cojag_devices(device_slot_interface &device)
{
device.option_add("hdd", COJAG_HARDDISK);
}
/*************************************
*
* Machine init
*
*************************************/
void jaguar_state::machine_start()
{
/* configure banks for gfx/sound ROMs */
if (m_romboard_region != nullptr)
{
uint8_t *romboard = m_romboard_region->base();
/* graphics banks */
if (m_maingfxbank.found())
{
m_maingfxbank->configure_entries(0, 2, romboard + 0x800000, 0x400000);
}
m_gpugfxbank->configure_entries(0, 2, romboard + 0x800000, 0x400000);
/* sound banks */
m_mainsndbank->configure_entries(0, 8, romboard + 0x000000, 0x200000);
m_dspsndbank->configure_entries(0, 8, romboard + 0x000000, 0x200000);
}
}
void jaguar_state::machine_reset()
{
m_protection_check = 0;
/* 68020 only: copy the interrupt vectors into RAM */
if (!m_is_r3000)
{
if (m_rom_base.found())
{
for (offs_t addr = 0; addr < 0x400; addr += 4) // do not increase, or Doom breaks
m_shared_ram[addr/4] = m_rom_base[addr/2] << 16 | m_rom_base[addr/2+1];
}
else
std::copy_n(reinterpret_cast<uint32_t *>(memregion("maincpu")->base()), 0x100, &m_shared_ram[0]);
}
/* reset banks for gfx/sound ROMs */
if (m_romboard_region != nullptr)
{
/* graphics banks */
if (m_maingfxbank.found())
{
m_maingfxbank->set_entry(0);
}
m_gpugfxbank->set_entry(0);
/* sound banks */
m_mainsndbank->set_entry(0);
m_dspsndbank->set_entry(0);
}
/* clear any spinuntil stuff */
gpu_resume();
dsp_resume();
/* halt the CPUs */
m_gpu->go_w(false);
m_dsp->go_w(false);
/* set blitter idle flag */
m_blitter_status = 1;
m_joystick_data = 0xffffffff;
m_eeprom_bit_count = 0;
if ((m_using_cart) && (m_config_io->read() & 2))
{
m_cart_base[0x102] = 1;
m_using_cart = false;
}
}
void jaguarcd_state::machine_reset()
{
jaguar_state::machine_reset();
m_shared_ram[0x4/4] = 0x00802000; /* hack until I understand */
m_butch_cmd_index = 0;
m_butch_cmd_size = 1;
}
/********************************************************************
*
* EEPROM
* ======
*
* The EEPROM is accessed by a serial protocol using the registers
* 0xF14000 (read data), F14800 (increment clock, write data), F15000 (reset for next word)
*
********************************************************************/
/*
emu_file jaguar_state::*jaguar_nvram_fopen( uint32_t openflags)
{
device_image_interface *image = dynamic_cast<device_image_interface *>(machine().device("cart"));
osd_file::error filerr;
emu_file *file;
if (image->exists())
{
std::string fname(machine().system().name, PATH_SEPARATOR, image->basename_noext(), ".nv");
filerr = mame_fopen( SEARCHPATH_NVRAM, fname, openflags, &file);
return (filerr == osd_file::error::NONE) ? file : nullptr;
}
else
return nullptr;
}
void jaguar_state::jaguar_nvram_load()
{
emu_file *nvram_file = nullptr;
device_t *device;
for (device = machine().m_devicelist.first(); device != nullptr; device = device->next())
{
device_nvram_func nvram = (device_nvram_func)device->get_config_fct(DEVINFO_FCT_NVRAM);
if (nvram != nullptr)
{
if (nvram_file == nullptr)
nvram_file = jaguar_nvram_fopen(machine, OPEN_FLAG_READ);
(*nvram)(device, nvram_file, 0);
}
}
if (nvram_file != nullptr)
mame_fclose(nvram_file);
}
void jaguar_state::jaguar_nvram_save()
{
emu_file *nvram_file = nullptr;
device_t *device;
for (device = machine().m_devicelist.first(); device != nullptr; device = device->next())
{
device_nvram_func nvram = (device_nvram_func)device->get_config_fct(DEVINFO_FCT_NVRAM);
if (nvram != nullptr)
{
if (nvram_file == nullptr)
nvram_file = jaguar_nvram_fopen(machine, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
// check nvram_file to avoid crash when no image is mounted or cannot be created
if (nvram_file)
(*nvram)(device, nvram_file, 1);
}
}
if (nvram_file != nullptr)
mame_fclose(nvram_file);
}
static NVRAM_HANDLER( jaguar )
{
if (read_or_write) {
jaguar_nvram_save(machine);
}
else
{
if (file)
jaguar_nvram_load(machine);
}
}
*/
void jaguar_state::eeprom_w(uint32_t data)
{
m_eeprom_bit_count++;
if (m_eeprom_bit_count != 9) /* kill extra bit at end of address */
{
m_eeprom->di_write(data >> 31);
m_eeprom->clk_write(0);
m_eeprom->clk_write(1);
}
}
uint32_t jaguar_state::eeprom_clk()
{
if (!machine().side_effects_disabled())
{
m_eeprom->clk_write(0);
m_eeprom->clk_write(1); /* get next bit when reading */
}
return 0;
}
uint32_t jaguar_state::eeprom_cs()
{
if (!machine().side_effects_disabled())
{
m_eeprom->cs_write(CLEAR_LINE); /* must do at end of an operation */
m_eeprom->cs_write(ASSERT_LINE); /* enable chip for next operation */
m_eeprom->di_write(1); /* write a start bit */
m_eeprom->clk_write(0);
m_eeprom->clk_write(1);
m_eeprom_bit_count = 0;
}
return 0;
}
/*************************************
*
* Misc. control bits
*
*************************************/
uint32_t jaguar_state::misc_control_r()
{
/* D7 = board reset (low)
D6 = audio must & reset (high)
D5 = volume control data (invert on write)
D4 = volume control clock
D3-D1 = audio bank 2-0
D0 = shared memory select (0=XBUS) */
return m_misc_control_data ^ 0x20;
}
void jaguar_state::misc_control_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
logerror("%s:misc_control_w(%02X)\n", machine().describe_context(), data);
/* D7 = board reset (low)
D6 = audio must & reset (high)
D5 = volume control data (invert on write)
D4 = volume control clock
D3-D1 = audio bank 2-0
D0 = shared memory select (0=XBUS) */
/* handle resetting the DSPs */
if (!(data & 0x80))
{
/* clear any spinuntil stuff */
gpu_resume();
dsp_resume();
/* halt the CPUs */
m_gpu->go_w(false);
m_dsp->go_w(false);
}
/* adjust banking */
if (m_romboard_region != nullptr)
{
m_mainsndbank->set_entry((data >> 1) & 7);
m_dspsndbank->set_entry((data >> 1) & 7);
}
COMBINE_DATA(&m_misc_control_data);
}
/*************************************
*
* 32-bit access to the GPU
*
*************************************/
uint32_t jaguar_state::gpuctrl_r(offs_t offset, uint32_t mem_mask)
{
return m_gpu->iobus_r(offset, mem_mask);
}
void jaguar_state::gpuctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
m_gpu->iobus_w(offset, data, mem_mask);
}
/*************************************
*
* 32-bit access to the DSP
*
*************************************/
uint32_t jaguar_state::dspctrl_r(offs_t offset, uint32_t mem_mask)
{
return m_dsp->iobus_r(offset, mem_mask);
}
void jaguar_state::dspctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
m_dsp->iobus_w(offset, data, mem_mask);
}
/*************************************
*
* Input ports
*
* Information from "The Jaguar Underground Documentation"
* by Klaus and Nat!
*
*************************************/
uint32_t jaguar_state::joystick_r()
{
uint16_t joystick_result = 0xfffe;
uint16_t joybuts_result = 0xffef;
/*
* 16 12 8 4 0
* +---------+---------+---------^---------+
* | pad 1 | pad 0 | unused |
* +---------+---------+-------------------+
* 15...12 11...8 7...0
*
* Reading this register gives you the output of the selected columns
* of the pads.
* The buttons pressed will appear as cleared bits.
* See the description of the column addressing to map the bits
* to the buttons.
*/
for (int i = 0; i < 8; i++)
{
if ((m_joystick_data & (0x10000 << i)) == 0)
{
joystick_result &= m_joy[i]->read();
joybuts_result &= m_buttons[i]->read();
}
}
joystick_result |= m_eeprom->do_read();
joybuts_result |= (m_config_io->read() & 0x10);
return (joystick_result << 16) | joybuts_result;
}
void jaguar_state::joystick_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
/*
* 16 12 8 4 0
* +-+-------^------+--+---------+---------+
* |r| unused |mu| col 1 | col 0 |
* +-+--------------+--+---------+---------+
* 15 8 7...4 3...0
*
* col 0: column control of joypad 0
*
* Here you select which column of the joypad to poll.
* The columns are:
*
* Joystick Joybut
* col_bit|11 10 9 8 1 0
* -------+--+--+--+-- ---+------
* 0 | R L D U A PAUSE (RLDU = Joypad directions)
* 1 | 1 4 7 * B
* 2 | 2 5 8 0 C
* 3 | 3 6 9 # OPTION
*
* You select a column my clearing the appropriate bit and setting
* all the other "column" bits.
*
*
* col1: column control of joypad 1
*
* This is pretty much the same as for joypad EXCEPT that the
* column addressing is reversed (strange!!)
*
* Joystick Joybut
* col_bit|15 14 13 12 3 2
* -------+--+--+--+-- ---+------
* 4 | 3 6 9 # OPTION
* 5 | 2 5 8 0 C
* 6 | 1 4 7 * B
* 7 | R L D U A PAUSE (RLDU = Joypad directions)
*
* mute (mu): sound control
*
* You can turn off the sound by clearing this bit.
*
* read enable (r):
*
* Set this bit to read from the joysticks, clear it to write
* to them.
*/
COMBINE_DATA(&m_joystick_data);
}
/*************************************
*
* Output ports
*
*************************************/
void jaguar_state::latch_w(uint32_t data)
{
logerror("%08X:latch_w(%X)\n", m_maincpu->pcbase(), data);
/* adjust banking */
if (m_romboard_region != nullptr)
{
if (m_maingfxbank.found())
{
m_maingfxbank->set_entry(data & 1);
}
m_gpugfxbank->set_entry(data & 1);
}
}
/*************************************
*
* EEPROM access
*
*************************************/
uint32_t jaguar_state::eeprom_data_r(offs_t offset)
{
if (m_is_r3000)
return m_nvram[offset] | 0xffffff00;
else
return m_nvram[offset] | 0x00ffffff;
}
void jaguar_state::eeprom_enable_w(uint32_t data)
{
m_eeprom_enable = true;
}
void jaguar_state::eeprom_data_w(offs_t offset, uint32_t data)
{
// if (m_eeprom_enable)
{
if (m_is_r3000)
m_nvram[offset] = data & 0x000000ff;
else
m_nvram[offset] = data & 0xff000000;
}
// else
// logerror("%s:error writing to disabled EEPROM\n", machine().describe_context());
m_eeprom_enable = false;
}
/*************************************
*
* GPU synchronization & speedup
*
*************************************/
/*
Explanation:
The GPU generally sits in a tight loop waiting for the main CPU to store
a jump address into a specific memory location. This speedup is designed
to catch that loop, which looks like this:
load (r28),r21
jump (r21)
nop
When nothing is pending, the GPU keeps the address of the load instruction
at (r28) so that it loops back on itself. When the main CPU wants to execute
a command, it stores an alternate address to (r28).
Even if we don't optimize this case, we do need to detect when a command
is written to the GPU in order to improve synchronization until the GPU
has finished. To do this, we start a temporary high frequency timer and
run it until we get back to the spin loop.
*/
void jaguar_state::gpu_jump_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
/* update the data in memory */
COMBINE_DATA(m_gpu_jump_address);
logerror("%08X:GPU jump address = %08X\n", m_gpu->pcbase(), *m_gpu_jump_address);
/* if the GPU is suspended, release it now */
gpu_resume();
/* start the sync timer going, and note that there is a command pending */
m_gpu_sync_timer->adjust(attotime::zero);
m_gpu_command_pending = true;
}
uint32_t jaguar_state::gpu_jump_r()
{
/* if the current GPU command is just pointing back to the spin loop, and */
/* we're reading it from the spin loop, we can optimize */
if (*m_gpu_jump_address == m_gpu_spin_pc && m_gpu->pcbase() == m_gpu_spin_pc)
{
#if ENABLE_SPEEDUP_HACKS
/* spin if we're allowed */
if (m_hacks_enabled) gpu_suspend();
#endif
/* no command is pending */
m_gpu_command_pending = false;
}
/* return the current value */
return *m_gpu_jump_address;
}
/*************************************
*
* Main CPU speedup (R3000 games)
*
*************************************/
/*
Explanation:
Instead of sitting in a tight loop, the CPU will run the random number
generator over and over while waiting for an interrupt. In order to catch
that, we snoop the memory location it is polling, and see if it is read
at least 5 times in a row, each time less than 200 cycles apart. If so,
we assume it is spinning. Also, by waiting for 5 iterations, we let it
crank through some random numbers, just not several thousand every frame.
*/
#if ENABLE_SPEEDUP_HACKS
uint32_t jaguar_state::cojagr3k_main_speedup_r()
{
uint64_t curcycles = m_maincpu->total_cycles();
/* if it's been less than main_speedup_max_cycles cycles since the last time */
if (curcycles - m_main_speedup_last_cycles < m_main_speedup_max_cycles)
{
/* increment the count; if we hit 5, we can spin until an interrupt comes */
if (m_main_speedup_hits++ > 5)
{
m_maincpu->spin_until_interrupt();
m_main_speedup_hits = 0;
}
}
/* if it's been more than main_speedup_max_cycles cycles, reset our count */
else
m_main_speedup_hits = 0;
/* remember the last cycle count */
m_main_speedup_last_cycles = curcycles;
/* return the real value */
return *m_main_speedup;
}
#endif
/*************************************
*
* Additional main CPU speedup
* (Freeze only)
*
*************************************/
/*
Explanation:
The main CPU hands data off to the GPU to process. But rather than running
in parallel, the main CPU just sits and waits for the result. This speedup
makes sure we don't waste time emulating that spin loop.
*/
#if ENABLE_SPEEDUP_HACKS
uint32_t jaguar_state::main_gpu_wait_r()
{
if (m_gpu_command_pending)
m_maincpu->spin_until_interrupt();
return *m_main_gpu_wait;
}
#endif
/*************************************
*
* Main CPU speedup (Area 51)
*
*************************************/
/*
Explanation:
Very similar to the R3000 code, except we need to verify that the value in
*main_speedup is actually 0.
*/