-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.c
1544 lines (1302 loc) · 46.3 KB
/
main.c
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
/* *********************************************************************
SMS Test Suite - by sverx
("largely inspired by Artemio's 240p, but not a fork of it!")
************************************************************************ */
#define MAJOR_VER 0
#define MINOR_VER 35
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>=(b))?(a):(b))
#include <stdio.h>
#include <stdbool.h>
#define MD_PAD_SUPPORT
#define VDPTYPE_DETECTION
#include "../SMSlib/SMSlib.h"
#include "../PSGlib/PSGlib.h"
#include "bank1.h"
#define MAIN_MENU_ITEMS 5
const unsigned char * const main_menu[MAIN_MENU_ITEMS] = {"Video Tests",
"Audio Tests",
"Pad Tests",
"System Info",
"Paddle Tests"};
#define VIDEO_MENU_ITEMS 10
const unsigned char * const video_menu[VIDEO_MENU_ITEMS] = {"PLUGE",
"Color bars",
"Color bleed",
"Grid",
"Stripes/Checks",
"Full colors",
"Linearity",
"Drop Shadow",
"Striped sprite",
"[ back ]"};
#define AUDIO_MENU_ITEMS 4
const unsigned char * const audio_menu[AUDIO_MENU_ITEMS] = {"PSG chip audio",
"FM chip audio",
"Combined audio",
"[ back ]"};
#define BIOSES_ITEMS 14
const struct {
const unsigned int sum8k;
const unsigned char * const name;
} BIOSes[BIOSES_ITEMS] = {
{0x9204,"Alex Kidd in Miracle World"},
{0x9ec6,"Hang On & Safari Hunt"}, // MPR 11459 (first version "Hang On & Safari Hunt")
{0x8738,"Hang On & Safari Hunt [A]"}, // MPR 11459-A (amended "Hang On & Safari Hunt", revision 'A')
{0x7f6f,"Hang On"},
{0xde36,"Sonic the Hedgehog"},
{0xf124,"Missile Defense 3-D"},
{0xaf19,"Samsung Gam*Boy/Aladdin Boy"}, // this has AKiMW game in it
{0xef78,"US-European SMS BIOS v1.3"},
{0x95c3,"Japanese SMS BIOS v2.1"},
{0x934d,"M404 Prototype BIOS"},
{0x5f04,"Prototype BIOS v1.0"},
{0xe8b0,"SMS BIOS v2.0"},
{0xdc4e,"Store Display Unit BIOS"}, // not sure this is really useful
{0x251c,"Emulicious (emulator) BIOS"} // (accurate at 11 Nov 2024)
};
#define GG_BIOSES_ITEMS 2
const struct {
const unsigned int sum1k;
const unsigned char * const name;
} GG_BIOSes[GG_BIOSES_ITEMS] = {
{0x5e3a,"Majesco GameGear BIOS"},
{0x207e,"Emulicious (emulator) GG BIOS"} // ;)
};
#define MENU_FIRST_ROW 8
#define MENU_FIRST_COL 4
#define FOOTER_COL 1
#define FOOTER_ROW 21
unsigned char cur_menu_item, main_menu_items, pointer_anim;
/* hardware tests results */
unsigned char TV_model;
bool is_Japanese, has_new_VDP, do_Port3E_works, has_CMOS_CPU;
bool is_MegaDrive, is_GameGear;
bool has_BIOS_GG, has_2ASIC_GG;
unsigned char FMfeatures;
unsigned char some_paddle_connected;
/* VDP sprite zoom capabilities */
#define SZC_ABSENT 0
#define SZC_PARTIAL 1
#define SZC_COMPLETE 2
/* ****************** for PADS TESTS *********************** */
#define COLOR_UP 10
#define COLOR_DOWN 12
#define COLOR_LEFT 5
#define COLOR_RIGHT 6
#define COLOR_1 2
#define COLOR_2 11
#define COLOR_A 7
#define COLOR_X 9
#define COLOR_Y 3
#define COLOR_Z 4
#define COLOR_START 8
#define COLOR_MODE 1
#define COLOR_RESET 13
#define COLOR_PAUSE 14
#define HILIT_COLOR 0x2F
#define BLACK 0x00
/* ****************** for PADDLE TESTS *********************** */
#define COLOR_PADDLE_A 10
#define COLOR_PADDLE_B 12
#define COLOR_PADDLE_A_1 2
#define COLOR_PADDLE_B_1 11
#define PADDLE_THRESHOLD 8
#define APPROX_1_SEC 55
#define APPROX_3_SECS (APPROX_1_SEC*3)
#define PAUSE_TIMEOUT APPROX_1_SEC
/* *********** for running code in RAM ******************* */
#define CODE_IN_RAM_SIZE 256
#define TEMP_BUF_SIZE (4*1024)
// #define CART_CHECK_ADDR 0x7F00
#define CART_CHECK_ADDR 0x0100
#define CART_CHECK_SIZE 256
unsigned char pause_cnt;
unsigned int kp,kr,mp,mr,ks;
unsigned char code_in_RAM[CODE_IN_RAM_SIZE]; // 256 bytes should be enough for everything
unsigned char temp_buf[TEMP_BUF_SIZE];
#define BIOS_SIZE_8K 0x20
#define BIOS_SIZE_1K 0x04
/* ******** for GameGear Twin Asic detection ************* */
#define VDP_CTRL_PORT 0xbf
#define VDP_DATA_PORT 0xbe
#define VRAM_AREA_READ_ADDRESS (0x3800+32*24*2)
#define VRAM_AREA_WRTE_ADDRESS (0x4000+VRAM_AREA_READ_ADDRESS)
#define VRAM_XFER_LENGTH_BYTES 256
#define VRAM_XFER_LENGTH_DWORDS (VRAM_XFER_LENGTH_BYTES/4)
#define VRAM_DATA_1ST_BYTE 0xAA
#define VRAM_DATA_2ND_BYTE 0x55
#define VRAM_DATA_3RD_BYTE 0x12
#define VRAM_DATA_4TH_BYTE 0xED
#define VRAM_DATA_DWORD (((unsigned long)VRAM_DATA_4TH_BYTE << 24)|((unsigned long)VRAM_DATA_3RD_BYTE << 16)|((unsigned long)VRAM_DATA_2ND_BYTE << 8)|(unsigned long)VRAM_DATA_1ST_BYTE)
#define RAM_CODE_SIZE 128
unsigned long ram_buffer[VRAM_XFER_LENGTH_DWORDS];
/* ******** for FM audio chip detection ************* */
// possible detection results are:
#define SMS_AUDIO_NO_FM 0
#define SMS_AUDIO_FM_ONLY 1
#define SMS_AUDIO_FM_PSG 2
#define SMS_ENABLE_AUDIO_FM_ONLY 0x01
#define SMS_ENABLE_AUDIO_FM_PSG 0x03
#define SMS_ENABLE_AUDIO_PSG_ONLY 0x00
#define SMS_ENABLE_AUDIO_NONE 0x02
/* **************** [[[ CODE ]]] ************************** */
unsigned char check_VRAM_contents (void) __naked __z88dk_fastcall {
__asm
ld hl,#VRAM_AREA_READ_ADDRESS ; read from VRAM
ld c,#VDP_CTRL_PORT ; set VDP Control Port
di ; make it interrupt SAFE
out (c),l
out (c),h
ei
ld b,#VRAM_XFER_LENGTH_DWORDS
ld c,#VDP_DATA_PORT
ld l,#1 ; report error
_loopRead:
nop
nop
nop
nop
nop
nop
nop
nop ; 32 cycles wait
in a,(c)
cp #VRAM_DATA_1ST_BYTE
ret nz
nop
nop
nop
nop
nop
nop
nop
nop ; 32 cycles wait
in a,(c)
cp #VRAM_DATA_2ND_BYTE
ret nz
nop
nop
nop
nop
nop
nop
nop
nop ; 32 cycles wait
in a,(c)
cp #VRAM_DATA_3RD_BYTE
ret nz
nop
nop
nop
nop
nop
nop
nop
nop ; 32 cycles wait
in a,(c)
cp #VRAM_DATA_4TH_BYTE
ret nz
djnz _loopRead
ld l,#0 ; report OK
ret
__endasm;
}
void copy_VRAM_26 (void) __naked {
__asm
ld hl,#VRAM_AREA_WRTE_ADDRESS ; write to VRAM
ld c, #0xBF ; set VDP Control Port
di ; make it interrupt SAFE
out (c),l
out (c),h
ei ; 4
ld hl,#_ram_buffer ; 10
ld b,#VRAM_XFER_LENGTH_BYTES/2 ; 7
ld c,#0xBE ; 7 = 28 ( > 26 )
di
_loop_copy_26:
outi ; 16
jp nz,_loop_copy_26 ; 10 = 26
ld b,#VRAM_XFER_LENGTH_BYTES/2 ; 7 - the delay between halves must be an ODD number of cycles
_loop_copy_26_again:
outi ; 16
jp nz,_loop_copy_26_again ; 10 = 26
ei
ret
__endasm;
}
bool is_TwinAsic_GG (void) {
unsigned char i,count;
for (i=0;i<VRAM_XFER_LENGTH_DWORDS;i++)
ram_buffer[i]=VRAM_DATA_DWORD;
SMS_waitForVBlank();
SMS_VRAMmemset(VRAM_AREA_WRTE_ADDRESS, 0x00, VRAM_XFER_LENGTH_BYTES);
// make sure we're drawing the screen the moment we run the test
do
count=SMS_getVCount();
while ((count<64) || (count>=160));
copy_VRAM_26();
return (check_VRAM_contents());
}
unsigned int compute_BIOS_sum (void) __naked __z88dk_fastcall {
/* *************************
NOTE: this code will be copied to RAM and run from there!
************************* */
__asm
di ; interrupts should be disabled!
ld a,#0b11100011 ; reset bits 4,3 (enable RAM/BIOS) and set bits 5,6,7 (to disable card/cartridge/expansion)
out (#0x3E),a ; do!
ld de,#0 ; sum
ld hl,#0x0000 ; src
loop:
ld a,(hl) ; a=*src
add a,e
ld e,a
jr nc,nocarry
inc d
nocarry:
inc hl ; src++
ld a,h
cp c ; size to check preloaded in C by caller
jr nz,loop
ex de,hl ; hl=sum
; ld a,#0b10101011 ; reset bits 4,6 (enable RAM/cartridge) and set bits 3,5,7 (to disable BIOS/card/expansion)
ld a,(_SMS_Port3EBIOSvalue)
out (#0x3E),a ; restore it
ei ; re-enable interrupts!
ret ; because I am naked ;)
__endasm;
}
#pragma save
#pragma disable_warning 85
unsigned int get_BIOS_sum (unsigned char size) __naked __z88dk_fastcall {
__asm
ld a,l ; save size in A
ld hl,#_compute_BIOS_sum
ld de,#_code_in_RAM
ld bc,#CODE_IN_RAM_SIZE
ldir ; copy code in RAM
ld c,a ; restore size in C
jp _code_in_RAM
__endasm;
}
#pragma restore
void ldir_BIOS_SRAM (void) __naked {
/* *************************
NOTE: this code will be copied to RAM and run from there!
************************* */
__asm
di ; interrupts should be disabled!
; 1st half ***********
ld hl,#0x0000 ; src (BIOS)
ld de,#0x8000 ; dst (SRAM)
ld b,#4 ; 4 times (4 times 4KB)
outloop1:
push bc
ld a,#0b11100011 ; reset bits 3,4 (enable BIOS/RAM) and set bits 5,6,7 (to disable card/cartridge/expansion)
out (#0x3E),a ; do!
push de
ld de,#_temp_buf ; dst (RAM)
ld bc,#TEMP_BUF_SIZE ; 4K
ldir
; ld a,#0b10101011 ; reset bits 4,6 (enable RAM/cartridge) and set bits 3,5,7 (to disable BIOS/card/expansion)
ld a,(_SMS_Port3EBIOSvalue)
out (#0x3E),a ; restore it
pop de
push hl
ld hl,#_temp_buf ; src (RAM)
ld bc,#TEMP_BUF_SIZE ; 4K
ldir
pop hl
pop bc
djnz outloop1
/* *************************************
// ---> My Master EverDrive is the old model
// and doesn't seem to support 32 KB saves :(
ld a,#0x0C ; select SRAM bank 2
ld (#0xfffc),a
; 2nd half ***********
ld b,#4 ; 4 times
ld de,#0x8000 ; dst (SRAM)
outloop2:
push bc
ld a,#0b11100011 ; reset bits 3,4 (enable BIOS/RAM) and set bits 5,6,7 (to disable card/cartridge/expansion)
out (#0x3E),a ; do!
push de
ld de,#_temp_buf ; dst (RAM)
ld bc,#TEMP_BUF_SIZE ; 4K
ldir
ld a,#0b10101011 ; reset bits 4,6 (enable RAM/cartridge) and set bits 3,5,7 (to disable BIOS/card/expansion)
out (#0x3E),a ; restore it
pop de
push hl
ld hl,#_temp_buf ; src (RAM)
ld bc,#TEMP_BUF_SIZE ; 4K
ldir
pop hl
pop bc
djnz outloop2
************************************* */
ei ; re-enable interrupts!
ret ; because I am naked ;)
__endasm;
}
void dump_BIOS (void) __naked {
__asm
ld hl,#_ldir_BIOS_SRAM
ld de,#_code_in_RAM
ld bc,#CODE_IN_RAM_SIZE
ldir ; copy code in RAM
jp _code_in_RAM
__endasm;
}
unsigned char detect_Port3E_match (void) __naked __z88dk_fastcall {
/* *************************
NOTE: this code will be copied to RAM and run from there!
************************* */
__asm
di ; interrupts should be disabled!
ld a,(_SMS_Port3EBIOSvalue)
; or #0xE0 ; set bits 5,6,7 (to disable card/cartridge/expansion)
or l ; set these bits to disable medias/stuff
and h ; reset these bits to enable medias/stuff
out (#0x3E),a ; do! (should have NO effect on a GameGear and on a Mark III)
ld hl,#CART_CHECK_ADDR
ld de,#_temp_buf
ld b,#CART_CHECK_SIZE
match_loop:
ld a,(de)
cp (hl)
jr nz,no_match ; check if I can still read from card/cartridge/expansion
inc hl
inc de
djnz match_loop
ld l,#0 ; I can: port3E is *not* effective
jr cont
no_match:
ld l,#1 ; I failed: port3E *is* effective
cont:
ld a,(_SMS_Port3EBIOSvalue)
out (#0x3E),a ; restore port 0x3E
ei ; re-enable interrupts!
ret ; because I am naked ;)
__endasm;
}
#pragma save
#pragma disable_warning 85
bool is_Port3E_effective (unsigned int masks) __naked __z88dk_fastcall {
__asm
push hl
ld hl,#CART_CHECK_ADDR
ld de,#_temp_buf
ld bc,#CART_CHECK_SIZE
ldir ; copy some bytes from card/cartridge/expansion to RAM
ld hl,#_detect_Port3E_match
ld de,#_code_in_RAM
ld bc,#CODE_IN_RAM_SIZE
ldir ; copy code in RAM
pop hl
jp _code_in_RAM
__endasm;
}
#pragma restore
bool isJapanese (void) __naked __z88dk_fastcall {
/* ==============================================================
Region detector
Returns 1 for Japanese, 0 for export
Based on code found in many Sega games (eg. Super Tennis)
============================================================== */
/* *** taken from http://www.smspower.org/Development/RegionDetection *** */
__asm
ld a,#0b11110101 ; Output 1s on both TH lines
out (#0x3f),a
in a,(#0xdd)
and #0b11000000 ; See what the TH inputs are
cp #0b11000000 ; If the input does not match the output then it is a Japanese system
jp nz,_IsJap
ld a,#0b01010101 ; Output 0s on both TH lines
out (#0x3f),a
in a,(#0xdd)
and #0b11000000 ; See what the TH inputs are
jp nz,_IsJap ; If the input does not match the output then it is a Japanese system
ld a,#0b11111111 ; Set everything back to being inputs
out (#0x3f),a
ld l,#0
ret
_IsJap:
ld l,#1
ret
__endasm;
}
#pragma save
#pragma disable_warning 85
bool paddle_detection (unsigned char which) __naked __z88dk_fastcall {
__asm
ld a,l
or a
ld bc,#0
jr nz, detect_second_pad
read:
in a,(#0xDC)
and #0x20
jr nz, skip_inc
inc c
skip_inc:
djnz read
jr discriminate
detect_second_pad:
in a,(#0xDD)
and #08
jr nz, skip_inc_2
inc c
skip_inc_2:
djnz detect_second_pad
discriminate:
ld a,c
ld l,#0 ; set false
sub #0x60
ret c
cp #0x40
ret nc
inc l ; set true
ret
__endasm;
}
unsigned char read_paddle (unsigned char which) __naked __z88dk_fastcall {
__asm
ld a,l
or a
jr nz, read_second_pad
wait_5_reset:
in a,(#0xDC)
bit 5,a
jr nz, wait_5_reset ; wait until bit 5 is 0
and #0x0F
ld l,a ; save lower 4 bits into l
wait_5_set:
in a,(#0xDC)
bit 5,a
jr z, wait_5_set ; wait until bit 5 is 1
and #0x0F ; save lower 4 bits
add a,a
add a,a
add a,a
add a,a
or l ; move to high nibble
ld l,a ; together with lower part
ret
read_second_pad:
ld c,#0xDC
wait_3_reset:
in a,(#0xDD) ; ensure we are reading both ports same moment
ld e,a
in b,(c)
in a,(#0xDD)
or e
bit 3,a
jr nz, wait_3_reset ; wait until bit 5 is 0
ld a,b
and #0xC0 ; save upper 2 bits
rlca
rlca
ld l,a ; into l (bits 0,1)
ld a,e
and #0x03 ; save lower 2 bits
rlca
rlca
or l ; together with l
ld l,a ; into l (bits 2,3)
wait_3_set:
in a,(#0xDD) ; ensure we are reading both ports same moment
ld e,a
in b,(c)
in a,(#0xDD)
and e
bit 3,a
jr z, wait_3_set ; wait until bit 5 is 1
ld a,b
and #0xC0 ; save upper 2 bits
rrca
rrca
ld h,a ; into h (bits 4,5)
ld a,e
and #0x03 ; save lower 2 bits
rrca
rrca
or h ; together with h (bits 6,7)
or l ; together with lower part
ld l,a
ret
__endasm;
}
#pragma restore
/*
unsigned char port0 (void) __naked {
__asm
in a,(#0)
ld l,a
ret
__endasm;
}
*/
unsigned char detectVDPSpriteZoomCapabilities (void) {
unsigned char i;
SMS_VRAMmemset (0x0000, 0xFF, 32); // a 'full' tile
SMS_useFirstHalfTilesforSprites(true);
SMS_setSpriteMode (SPRITEMODE_ZOOMED);
SMS_initSprites();
SMS_addSprite (0, 0, 0); // first sprite
SMS_addSprite (0, 15, 0); // second sprite, one pixel 'too' high (will overlap 1st sprite only if zooming is supported at all)
SMS_waitForVBlank(); // wait VBlank
SMS_copySpritestoSAT(); // copy sprites to SAT
SMS_waitForVBlank(); // wait next VBlank...
// ... and if it's a MD the collision flag will be OFF
if (!(SMS_VDPFlags & VDPFLAG_SPRITECOLLISION))
return (SZC_ABSENT); // sprite zoom absent (315-5313) ['Genesis/MegaDrive']
SMS_initSprites();
SMS_addSprite (0, 0, 0); // first sprite
SMS_addSprite (15, 0, 0); // second sprite, one pixel 'too' to the left (will overlap 1st sprite if it has been correctly zoomed horizontally)
SMS_waitForVBlank(); // wait VBlank
SMS_copySpritestoSAT(); // copy sprites to SAT
SMS_waitForVBlank(); // wait next VBlank...
// ... and if it's a fixed VDP the collision flag will be ON
if (SMS_VDPFlags & VDPFLAG_SPRITECOLLISION)
return(SZC_COMPLETE); // sprite zoom fully working (315-5246 or 315-5378) ['SMS II' or 'GameGear']
else
return(SZC_PARTIAL); // sprite zoom partially working (315-5124) ['SMS' or 'Mark III']
}
void draw_footer_and_ver (void) {
// print console model
SMS_setNextTileatXY(FOOTER_COL,FOOTER_ROW);
printf (" Model:");
if (is_MegaDrive)
printf ("Genesis/MegaDrive ");
else if (do_Port3E_works) {
if (has_new_VDP)
printf ("Master System II ");
else
printf ("Master System ");
} else { // !do_Port3E_works
if (has_new_VDP) {
if (has_2ASIC_GG)
printf ("Game Gear (Twin ASICs) "); // no port3E support, new VDP, Two ASICs
else
printf ("Game Gear (Single ASIC)"); // no port3E support, new VDP, One ASIC
}
else
printf ("Mark III "); // no port3E support, old VDP
}
// print region
SMS_setNextTileatXY(FOOTER_COL,FOOTER_ROW+1);
printf (" Region:");
if (is_Japanese)
printf ("JPN/KOR"); // Japanese/Korean
else if (TV_model & VDP_NTSC)
printf ("USA/BRA"); // not Japanese and 60 Hz => USA/Brasil
else if (TV_model & VDP_PAL)
printf ("EUR/AUS"); // not Japanese and 50 Hz => EUR/Australia
//~ else
//~ printf ("- ??? -"); // not Japanese and undetected TV (this shouldn't happen with current detection routine)
// print TV mode
printf (" TV:");
if (TV_model & VDP_PAL)
printf ("50Hz (PAL) ");
else if (TV_model & VDP_NTSC)
printf ("60Hz (NTSC)");
//~ else
//~ printf ("undetected "); // (this shouldn't happen with current detection routine)
// print if paddle is detected
if (some_paddle_connected) {
SMS_setNextTileatXY(FOOTER_COL,FOOTER_ROW-1);
printf (" Paddle Control found in [%c] ",(some_paddle_connected==0x01)?'1':'2');
}
// print if FM chip is detected
if (FMfeatures!=SMS_AUDIO_NO_FM) {
SMS_setNextTileatXY(FOOTER_COL+2,FOOTER_ROW-2);
printf (" FM audio chip detected! ");
}
// print program version (just under the title)
SMS_setNextTileatXY(3,4);
printf ("ver %d.%2d",MAJOR_VER,MINOR_VER);
}
void draw_menu (unsigned char *menu[], unsigned int max) {
unsigned char i;
for (i=0;i<max;i++) {
SMS_setNextTileatXY(MENU_FIRST_COL,MENU_FIRST_ROW+i);
printf (" %-16s",menu[i]);
}
}
void load_menu_assets (void) {
// load background tiles, map and palette
SMS_loadPSGaidencompressedTiles (BG__tiles__psgcompr,96);
SMS_loadSTMcompressedTileMap (0,0,BG__tilemap__stmcompr);
SMS_loadBGPalette(BG__palette__bin);
// load sprite tile, build palette, turn on text renderer
SMS_loadPSGaidencompressedTiles (arrow__tiles__psgcompr,256);
SMS_setSpritePaletteColor (0, RGB(0,0,0));
SMS_setSpritePaletteColor (1, RGB(3,3,3));
SMS_autoSetUpTextRenderer();
}
unsigned int filter_paddle(unsigned int value) {
if (some_paddle_connected & 0x01)
value&=~(PORT_A_KEY_2|PORT_A_KEY_UP|PORT_A_KEY_DOWN|PORT_A_KEY_LEFT|PORT_A_KEY_RIGHT);
if (some_paddle_connected & 0x02)
value&=~(PORT_B_KEY_2|PORT_B_KEY_UP|PORT_B_KEY_DOWN|PORT_B_KEY_LEFT|PORT_B_KEY_RIGHT);
return (value);
}
void static_screen (void* tiles, void* tilemap, void* palette, void* alt_tiles, void* alt_tiles_2) {
unsigned char alt=0;
SMS_displayOff();
SMS_initSprites();
SMS_copySpritestoSAT();
SMS_loadPSGaidencompressedTiles(tiles,0);
SMS_loadSTMcompressedTileMap (0,0,tilemap);
SMS_loadBGPalette(palette);
SMS_displayOn();
for (;;) {
SMS_waitForVBlank();
kp=filter_paddle(SMS_getKeysPressed());
if (kp & (PORT_A_KEY_2|PORT_B_KEY_2))
break;
if (kp & (PORT_A_KEY_1|PORT_B_KEY_1)) {
if (alt_tiles==NULL)
break;
else {
if (++alt==((alt_tiles_2==NULL)?2:3))
alt=0;
switch (alt) {
case 0:
SMS_loadPSGaidencompressedTiles(tiles,0);
break;
case 1:
SMS_loadPSGaidencompressedTiles(alt_tiles,0);
break;
default:
SMS_loadPSGaidencompressedTiles(alt_tiles_2,0);
break;
}
}
}
}
SMS_displayOff();
}
void drop_shadow_striped_sprite (bool striped) {
unsigned char frame=0,pos=0;
SMS_displayOff();
SMS_initSprites();
SMS_copySpritestoSAT();
SMS_loadZX7compressedTiles (AlexKidd__tiles__zx7,0);
SMS_loadSTMcompressedTileMap (0,0,AlexKidd__tilemap__stmcompr);
SMS_loadBGPalette(AlexKidd__palette__bin);
if (striped) {
SMS_loadPSGaidencompressedTiles (striped__tiles__psgcompr,256);
} else {
SMS_loadPSGaidencompressedTiles (drop__tiles__psgcompr,256);
}
SMS_zeroSpritePalette();
SMS_setSpriteMode(SPRITEMODE_TALL);
SMS_displayOn();
for (;;) {
SMS_initSprites();
ks=SMS_getKeysStatus();
if (striped) {
SMS_addTwoAdjoiningSprites (110+pos, 80+pos,0);
SMS_addTwoAdjoiningSprites (110+16+pos,80+pos,4);
SMS_addTwoAdjoiningSprites (110+pos, 80+16+pos,8);
SMS_addTwoAdjoiningSprites (110+16+pos,80+16+pos,12);
if (ks & (PORT_A_KEY_UP|PORT_A_KEY_LEFT|PORT_B_KEY_UP|PORT_B_KEY_LEFT))
pos--;
else if (ks & (PORT_A_KEY_DOWN|PORT_A_KEY_RIGHT|PORT_B_KEY_DOWN|PORT_B_KEY_RIGHT))
pos++;
} else {
SMS_addTwoAdjoiningSprites (32+pos,(64*frame)+pos,0);
SMS_addTwoAdjoiningSprites (32+16+pos,(64*frame)+pos,4);
SMS_addTwoAdjoiningSprites (32+pos,(64*frame)+pos+16,8);
SMS_addTwoAdjoiningSprites (32+16+pos,(64*frame)+pos+16,12);
SMS_addTwoAdjoiningSprites (96+pos,48+(64*frame)+pos,0);
SMS_addTwoAdjoiningSprites (96+16+pos,48+(64*frame)+pos,4);
SMS_addTwoAdjoiningSprites (96+pos,48+(64*frame)+pos+16,8);
SMS_addTwoAdjoiningSprites (96+16+pos,48+(64*frame)+pos+16,12);
SMS_addTwoAdjoiningSprites (160+pos,96+(64*frame)+pos,0);
SMS_addTwoAdjoiningSprites (160+16+pos,96+(64*frame)+pos,4);
SMS_addTwoAdjoiningSprites (160+pos,96+(64*frame)+pos+16,8);
SMS_addTwoAdjoiningSprites (160+16+pos,96+(64*frame)+pos+16,12);
pos++;
frame=1-frame;
}
SMS_waitForVBlank();
SMS_copySpritestoSAT();
kp=filter_paddle(SMS_getKeysPressed());
if (kp & (PORT_A_KEY_2|PORT_B_KEY_2|PORT_A_KEY_1|PORT_B_KEY_1))
break;
}
SMS_displayOff();
SMS_initSprites();
SMS_copySpritestoSAT();
SMS_setSpriteMode(SPRITEMODE_NORMAL);
}
void fullscreen (void) {
unsigned char which=0;
SMS_displayOff();
SMS_VRAMmemset (0x0000, 0x00, 32); // a 'empty' tile
SMS_VRAMmemset (XYtoADDR(0,0), 0x00, 32*28*2); // full map of 'empty' tiles
SMS_setBGPaletteColor (0, RGB(3,3,3));
SMS_displayOn();
for (;;) {
SMS_initSprites();
SMS_waitForVBlank();
SMS_copySpritestoSAT();
kp=filter_paddle(SMS_getKeysPressed());
if (kp & (PORT_A_KEY_2|PORT_B_KEY_2))
break;
if (kp & (PORT_A_KEY_1|PORT_B_KEY_1)) {
which=(which+1)%4;
switch (which) {
case 0:SMS_setBGPaletteColor (0, RGB(3,3,3)); break;
case 1:SMS_setBGPaletteColor (0, RGB(3,0,0)); break;
case 2:SMS_setBGPaletteColor (0, RGB(0,3,0)); break;
case 3:SMS_setBGPaletteColor (0, RGB(0,0,3)); break;
}
}
}
SMS_displayOff();
}
void video_tests (void) {
bool go_back=false;
draw_menu(video_menu, VIDEO_MENU_ITEMS);
draw_footer_and_ver();
cur_menu_item=0,pointer_anim=0;
while (!go_back) {
SMS_initSprites();
SMS_addSprite(MENU_FIRST_COL*8+(pointer_anim/8),(MENU_FIRST_ROW+cur_menu_item)*8,0);
SMS_waitForVBlank();
SMS_copySpritestoSAT();
if ((++pointer_anim)==7*8)
pointer_anim=0;
kp=filter_paddle(SMS_getKeysPressed());
if (kp & (PORT_A_KEY_UP|PORT_B_KEY_UP)) { // UP
if (cur_menu_item>0)
cur_menu_item--;
else
cur_menu_item=VIDEO_MENU_ITEMS-1;
pointer_anim=0;
}
if (kp & (PORT_A_KEY_DOWN|PORT_B_KEY_DOWN)) { // DOWN
if (cur_menu_item<(VIDEO_MENU_ITEMS-1))
cur_menu_item++;
else
cur_menu_item=0;
pointer_anim=0;
}
if (kp & (PORT_A_KEY_1|PORT_A_KEY_2|PORT_B_KEY_1|PORT_B_KEY_2)) {
switch (cur_menu_item) {
case 0:static_screen(PLUGE__tiles__psgcompr,PLUGE__tilemap__stmcompr,PLUGE__palette__bin,NULL,NULL); break;
case 1:static_screen(color_bars__tiles__psgcompr,color_bars__tilemap__stmcompr,color_bars__palette__bin,NULL,NULL); break;
case 2:static_screen(color_bleed__tiles__psgcompr,color_bleed__tilemap__stmcompr,color_bars__palette__bin,color_bleed2__tiles__psgcompr,NULL); break;
case 3:static_screen(grid__tiles__psgcompr,grid__tilemap__stmcompr,grid__palette__bin,NULL,NULL); break;
case 4:static_screen(stripes__tiles__psgcompr,fullscreen__tilemap__stmcompr,bw_palette_bin,v_stripes__tiles__psgcompr,checkerboard__tiles__psgcompr); break;
case 5:fullscreen(); break;
case 6:if ((!is_MegaDrive) && (!do_Port3E_works) && (has_new_VDP)) // if it's a GameGear
static_screen(linearity_GG__tiles__psgcompr,linearity_GG__tilemap__stmcompr,linearity__palette__bin,NULL,NULL);
else if (TV_model & VDP_PAL)
static_screen(linearity_PAL__tiles__psgcompr,linearity_PAL__tilemap__stmcompr,linearity__palette__bin,NULL,NULL);
else
static_screen(linearity_NTSC__tiles__psgcompr,linearity_NTSC__tilemap__stmcompr,linearity__palette__bin,NULL,NULL);
break;
case 7:drop_shadow_striped_sprite(false);break;
case 8:drop_shadow_striped_sprite(true);break;
case VIDEO_MENU_ITEMS-1:go_back=true; break;
}
if (!go_back) {
load_menu_assets();
draw_menu(video_menu, VIDEO_MENU_ITEMS);
draw_footer_and_ver();
}
}
}
cur_menu_item=0,pointer_anim=0;
}
void PSG_audio_test (void) {
SMS_displayOff();
SMS_initSprites();
SMS_copySpritestoSAT();
SMS_loadPSGaidencompressedTiles (controller__tiles__psgcompr,0);
SMS_loadSTMcompressedTileMap (0,0,controller__tilemap__stmcompr);
SMS_loadBGPalette(controller__palette__bin);
SMS_displayOn();
for(;;) {
SMS_waitForVBlank();
PSGFrame();
kp=filter_paddle(SMS_getKeysPressed());
if (kp & (PORT_A_KEY_UP|PORT_B_KEY_UP))
PSGPlay(CH0_psgc);
if (kp & (PORT_A_KEY_RIGHT|PORT_B_KEY_RIGHT))
PSGPlay(CH1_psgc);
if (kp & (PORT_A_KEY_DOWN|PORT_B_KEY_DOWN))
PSGPlay(CH2_psgc);
if (kp & (PORT_A_KEY_LEFT|PORT_B_KEY_LEFT))
PSGPlay(CH3_psgc);
if (kp & (PORT_A_KEY_1|PORT_B_KEY_1))
PSGPlay(VolumeTest_psgc);
if (kp & (PORT_A_KEY_2|PORT_B_KEY_2))
break;
}
PSGStop();
}
void audio_tests_menu(void) {
bool go_back=false;