This repository has been archived by the owner on May 2, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SLNES.cpp
5105 lines (4488 loc) · 144 KB
/
SLNES.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
/*******************************************************************
* Copyright (c) 2005,杭州士兰微电子股份有限公司 *
* All rights reserved. *
*******************************************************************
文件名称: SLNES.c
文件版本: 1.00
创建人员: 李政
创建日期: 2005/05/08 08:00:00
功能描述: NES模拟器的核心程序
修改记录:
*******************************************************************/
/*=================================================================*/
/* */
/* SLNES.c : NES Emulator for Win32, Linux(x86), Linux(LEON) */
/* */
/* 2004/07/28 SLNES Project */
/* */
/*=================================================================*/
/*-------------------------------------------------------------------
* File List :
*
* [NES Hardware]
* SLNES.cpp
* SLNES.h
*
* [Others]
* SLNES_Data.h
*
* [The function which depends on a system]
* SLNES_System_ooo.cpp (ooo is a system name. win, ...)
* SLNES_System.h
*
-------------------------------------------------------------------*/
/*-----------------------------------------------------------------*/
/* Include files */
/*-----------------------------------------------------------------*/
#include "SLNES.h"
#include "SLNES_Data.h"
#include "SLNES_System.h"
// 为了兼容.bin游戏代码中莫名其妙地与nes文件不同的地方(为了防止别人
// 开发VCD游戏机?):使用一些非官方的指令,例如将FF看作4C,将
// MapperWrite范围由标准的8000-FFFF扩展为6000-FFFF
#define damnBIN
// 如果只玩.bin游戏的话,可以简化一些代码以增加速度,大部分.nes游戏
// 也可以用HACK,当然如果速度够快的话还是不要用HACK为妙,但为了能在
// 32KB的ITCM里包含mapper1、7、11,就只能用HACK了,mapper4却是再没有
// 空间放了。
#define HACK
#if defined(PrintfFrameGraph) || defined(PrintfFrameClock)
unsigned int Frame = 0; // 已经过的游戏画面的桢数
#endif
/*-----------------------------------------------------------------*/
/* NES resources */
/*-----------------------------------------------------------------*/
/* RAM */
// 减容 #define RAM_SIZE 0x2000
#define RAM_SIZE 0x800
unsigned char RAM[RAM_SIZE];
/* ROM */
unsigned char *ROM;
/* ROM BANK (8KB * 4) */
unsigned char *ROMBANK0;
unsigned char *ROMBANK1;
unsigned char *ROMBANK2;
unsigned char *ROMBANK3;
unsigned char *memmap_tbl[8];
/* 6502 Flags */ //PSW
#define FLAG_C 0x01
#define FLAG_Z 0x02
#define FLAG_I 0x04
#define FLAG_D 0x08
#define FLAG_B 0x10
#define FLAG_R 0x20
#define FLAG_V 0x40
#define FLAG_N 0x80
/* Stack Address */
#define BASE_STACK 0x100
/* Interrupt Vectors */
#define VECTOR_NMI 0xfffa
#define VECTOR_RESET 0xfffc
#define VECTOR_IRQ 0xfffe
#define STEP_PER_SCANLINE 112 // 每一条扫描线所对应的6502时钟数
/*-----------------------------------------------------------------*/
/* PPU resources */
/*-----------------------------------------------------------------*/
unsigned char NTRAM[0x800]; // PPU真正的2KB内存
#define NAME_TABLE0 8
#define NAME_TABLE1 9
#define NAME_TABLE2 10
#define NAME_TABLE3 11
/* VROM */
unsigned char *VROM;
/* PPU BANK (1KB * 16) */
unsigned char *PPUBANK[16];
/* Sprite RAM */
#define SPRRAM_SIZE 256
unsigned char SPRRAM[SPRRAM_SIZE];
// 每个int的的低16位是当前扫描线上的Sprite的8个像素的调色板元素索引
// 值,从左到右的像素排列方式是02461357,如果某sprite有水平翻转属性的
// 话则是为75316420
int Sprites[64];
// 为负数(-1)则说明当前扫描线上没有sprite存在,为正数则范围为0-63
int FirstSprite;
#define SPR_Y 0
#define SPR_CHR 1
#define SPR_ATTR 2
#define SPR_X 3
#define SPR_ATTR_COLOR 0x3
#define SPR_ATTR_V_FLIP 0x80
#define SPR_ATTR_H_FLIP 0x40
#define SPR_ATTR_PRI 0x20
/* PPU Register */
unsigned char PPU_R0;
unsigned char PPU_R1;
unsigned char PPU_R2;
unsigned char PPU_R3;
unsigned char PPU_R7;
#define R0_NMI_VB 0x80
#define R0_NMI_SP 0x40
#define R0_SP_SIZE 0x20
#define R0_BG_ADDR 0x10
#define R0_SP_ADDR 0x08
#define R0_INC_ADDR 0x04
#define R0_NAME_ADDR 0x03
#define R1_BACKCOLOR 0xe0
#define R1_SHOW_SP 0x10
#define R1_SHOW_SCR 0x08
#define R1_CLIP_SP 0x04
#define R1_CLIP_BG 0x02
#define R1_MONOCHROME 0x01
#define R2_IN_VBLANK 0x80
#define R2_HIT_SP 0x40
#define R2_MAX_SP 0x20
#define R2_WRITE_FLAG 0x10
/* PPU Address */
int PPU_Addr;
int ARX; // X卷轴锁存器
int ARY; // Y卷轴锁存器
int NSCROLLX; // H(1位)->HT(5位)->FH(3位)组成的X卷轴计数器
int NSCROLLY; // V(1位)->VT(5位)->FV(3位)组成的Y卷轴计数器
unsigned char *NES_ChrGen; // 背景的PT在模拟器中的地址
unsigned char *NES_SprGen; // sprite的PT在模拟器中的地址
int PPU_Increment; // PPU Address的增加量(1或32)
/* Sprite Height */
int PPU_SP_Height;
/* VRAM Write Enable (0: Disable, 1: Enable) */
unsigned int byVramWriteEnable;
/* PPU Address and Scroll Latch Flag */
unsigned int PPU_Latch_Flag;
/*-----------------------------------------------------------------*/
/* Display and Others resouces */
/*-----------------------------------------------------------------*/
// 扫描线缓冲区数组,保存着一条扫描线的像素信息
unsigned char line_buffers[272];
unsigned char ZBuf[35];
// 指向扫描线缓冲区数组中将会显示在屏幕上的开始地址的指针,永远是
// line_buffers + 8
unsigned char *buf;
void PPU_Mirroring(int nType);
inline void PPU_CompareSprites(register int DY);
inline int PPU_DrawLine(register int DY, register int SY);
inline int PPU_RefreshSprites(unsigned char *Z);
/* Palette Table */
unsigned char PalTable[32];
/*-----------------------------------------------------------------*/
/* APU and Pad resources */
/*-----------------------------------------------------------------*/
void APU_Reset(void);
unsigned char APU_Read4015();
void APU_Write(unsigned int address, unsigned char value);
void APU_Reset(void);
void APU_Process(void);
void APU_Done(void);
#if BITS_PER_SAMPLE == 8
unsigned char wave_buffers[SAMPLE_PER_FRAME];
#else /* BITS_PER_SAMPLE */
short wave_buffers[SAMPLE_PER_FRAME];
#endif /* BITS_PER_SAMPLE */
unsigned int wave_buffers_count; // 模拟器向APU桢存中的某一桢传输采样值
/* Pad data */
unsigned int PAD1_Latch;
unsigned int PAD2_Latch;
unsigned int PAD_System;
unsigned int pad_strobe;
unsigned int PAD1_Bit;
unsigned int PAD2_Bit;
/*-----------------------------------------------------------------*/
/* ROM information */
/*-----------------------------------------------------------------*/
int RomSize;
int RomMask;
int VRomSize;
int VRomMask;
int MapperNo; // Mapper Number
int ROM_Mirroring; // Mirroring 0:Horizontal 1:Vertical
int ROM_SRAM;
/*=================================================================*/
/* */
/* 6502 Emulation */
/* */
/*=================================================================*/
void CPU_Reset();
void CPU_Step(unsigned short wClocks);
void CPU_NMI();
static inline unsigned char CPU_ReadIO(unsigned short wAddr);
static inline void CPU_WriteIO(unsigned short wAddr, unsigned char byData);
// Clock Op.
#define CLK(a) step_cycles += (a); \
total_cycles += (a);
// Addressing Op.
// 从PRG或RAM中读取操作码或操作数,然后nes_pc++
#define ReadPC(a) a = *nes_pc++
// 从PRG或RAM中读取操作数地址,然后nes_pc++
#define ReadPCW(a) a = *nes_pc++; a |= *nes_pc++ << 8
// 从PRG或RAM中读取操作数并加上nes_X,然后nes_pc++
// 中CIRCUS和Dragon Unit两款游戏只能使用上面一行
#define ReadPCX(a) a = (unsigned char)(*nes_pc++ + nes_X)
//#define ReadPCX(a) a = *nes_pc++ + nes_X
// 从PRG或RAM中读取操作数并加上nes_Y,然后nes_pc++
#ifdef HACK
#define ReadPCY(a) a = *nes_pc++ + nes_Y
#else /* HACK */
#define ReadPCY(a) a = (unsigned char)(*nes_pc++ + nes_Y)
#endif /* HACK */
// 从RAM中读取操作数地址
#define ReadZpW(a) a = RAM[a] | (RAM[a + 1] << 8)
// 从RAM中读取操作数
#define ReadZp(a) byD0 = RAM[a]
// 向RAM中写入操作数,经测试VCD游戏光盘中所有游戏皆可使用最后一行
//#define WriteZp(a, b) RAM[a & 0x7ff] = RAM[a & 0xfff] = RAM[a & 0x17ff] = RAM[a & 0x1fff] = b
//#define WriteZp(a, b) RAM[a & 0x7ff] = b
#define WriteZp(a, b) RAM[a] = b
// 从6502RAM中读取操作数
#define Read6502RAM(a) \
if (a >= 0x6000 || a < 0x2000) \
byD0 = memmap_tbl[a >> 13][a]; \
else \
byD0 = CPU_ReadIO(a);
// 向6502RAM中写入操作数
// 这里之所以将标准的“a < 0x8000”改为“a < 0x6000”是为了兼容
// mapper3的BIN文件里人为修改的游戏代码,也就是说,为了兼容BIN文
// 件而又不影响速度,同时还要兼顾.nes文件的存盘功能,这里把操作
// SRAM($6000-$7FFF)的代码放在了各个MapperWrite()函数中。
//#ifdef damnBIN
#define Write6502RAM(a, b) \
if (a < 0x2000) \
WriteZp(a, b); \
else if (a < 0x6000) \
CPU_WriteIO(a, b); \
else \
MapperWrite(a, b)
//#else /* damnBIN */
//#define Write6502RAM(a, b) \
// if (a < 0x2000) \
// WriteZp(a, b); \
// else if (a < 0x8000) \
// CPU_WriteIO(a, b); \
// else \
// MapperWrite(a, b)
//#endif /* damnBIN */
// Flag Op.
#define SETF(a) nes_F |= (a)
#define RSTF(a) nes_F &= ~(a)
#define TEST(a) RSTF(FLAG_N | FLAG_Z); SETF(byTestTable[a])
// Stack Op.
#define PUSH(a) RAM[BASE_STACK + nes_SP--] = (a)
#define PUSHW(a) PUSH((a) >> 8); PUSH((a) & 0xff)
#define POP(a) a = RAM[BASE_STACK + ++nes_SP]
#define POPW(a) POP(a); a |= (RAM[BASE_STACK + ++nes_SP] << 8)
// Shift Op.
#define M_FL(Rg) nes_F = (nes_F & ~(FLAG_Z | FLAG_N)) | byTestTable[Rg]
#define M_ASL(Rg) nes_F &= ~FLAG_C; \
nes_F |= Rg >> 7; \
Rg <<= 1; \
M_FL(Rg)
#define M_LSR(Rg) nes_F &= ~FLAG_C;\
nes_F |= Rg & FLAG_C; \
Rg >>= 1; \
M_FL(Rg)
#define M_ROL(Rg) byD1 = (Rg << 1) | (nes_F & FLAG_C); \
nes_F &= ~FLAG_C; \
nes_F |= Rg >> 7; \
Rg = byD1; \
M_FL(Rg)
#define M_ROR(Rg) byD1 = (Rg >> 1) | (nes_F << 7); \
nes_F &= ~FLAG_C; \
nes_F |= Rg & FLAG_C; \
Rg = byD1; \
M_FL(Rg)
#define ASLA M_ASL(nes_A)
#define ASL M_ASL(byD0)
#define LSRA M_LSR(nes_A)
#define LSR M_LSR(byD0)
#define ROLA M_ROL(nes_A)
#define ROL M_ROL(byD0)
#define RORA M_ROR(nes_A)
#define ROR M_ROR(byD0)
// 作用于ASL LSR ROL ROR四类对6502RAM进行位操作的指令
// 将各种可能只从RAM中读取的代码简化为只从RAM中读取,测遍VCD游戏光盘上
// 所有的游戏后都没问题
#ifdef HACK
#define Bit6502RAM(a) byD0 = RAM[wA0]; a; WriteZp(wA0, byD0)
#else /* HACK */
#define Bit6502RAM(a) \
if (wA0 < 0x2000) \
{ byD0 = RAM[wA0]; a; WriteZp(wA0, byD0); } \
else if (wA0 < 0x6000) \
{ byD0 = CPU_ReadIO(wA0); a; CPU_WriteIO(wA0, byD0); } \
else if (wA0 < 0x8000) \
{ byD0 = SRAM[wA0 & 0x1fff]; a; SRAM[wA0 & 0x1fff] = byD0; } \
else \
{ byD0 = memmap_tbl[wA0 >> 13][wA0]; a; MapperWrite(wA0, byD0); }
#endif /* HACK */
// Math Op. (nes_A D flag isn't being supported.)
// 作用于对6502RAM进行减一操作的DEC指令
#ifdef HACK
#define DEC6502RAM byD0 = RAM[wA0] - 1; WriteZp(wA0, byD0)
#else /* HACK */
#define DEC6502RAM \
if(wA0 < 0x2000) \
{ byD0 = RAM[wA0]; --byD0; WriteZp(wA0, byD0); } \
else if(wA0 < 0x6000) \
{ byD0 = CPU_ReadIO(wA0); --byD0; CPU_WriteIO(wA0, byD0); } \
else if(wA0 < 0x8000) \
{ byD0 = SRAM[wA0 & 0x1fff]; --byD0; SRAM[wA0 & 0x1fff] = byD0; } \
else \
{ byD0 = memmap_tbl[wA0 >> 13][wA0]; --byD0; MapperWrite(wA0, byD0); }
#endif /* HACK */
// 作用于对6502RAM进行加一操作的INC命令
#ifdef HACK
#define INC6502RAM byD0 = RAM[wA0] + 1; WriteZp(wA0, byD0)
#else /* HACK */
#define INC6502RAM \
if(wA0 < 0x2000) \
{ byD0 = RAM[wA0]; ++byD0; WriteZp(wA0, byD0); } \
else if(wA0 < 0x6000) \
{ byD0 = CPU_ReadIO(wA0); ++byD0; CPU_WriteIO(wA0, byD0); } \
else if(wA0 < 0x8000) \
{ byD0 = SRAM[wA0 & 0x1fff]; ++byD0; SRAM[wA0 & 0x1fff] = byD0; } \
else \
{ byD0 = memmap_tbl[wA0 >> 13][wA0]; ++byD0; MapperWrite(wA0, byD0); }
#endif /* HACK */
// Jump Op.
#define BRA(a) { \
if (a) \
{ \
ReadPC(BRAdisp); \
/*BRAtemp = nes_pc;*/ \
nes_pc += BRAdisp; \
CLK(3 /*+ ((BRAtemp & 0x0100) != (nes_pc & 0x0100))*/); \
} else { \
++nes_pc; \
CLK(2); \
} \
}
/*-----------------------------------------------------------------*/
/* valiables */
/*-----------------------------------------------------------------*/
REGISTER__nes_SP;
REGISTER__nes_F;
REGISTER__nes_A;
REGISTER__nes_X;
REGISTER__nes_Y;
REGISTER__nes_pc;
REGISTER__lastbank;
// 为了避免每次读取一个指令时就判断一次指令的位置,参考PocketNES中的
// 汇编代码,引入指向指令的指针:nes_pc,以及与之配合使用的lastbank
#define encodePC lastbank = memmap_tbl[((unsigned short)nes_pc) >> 13]; \
nes_pc = lastbank + (unsigned short)nes_pc
// 每次模拟6502时所经过的时钟周期数
unsigned int step_cycles;
// 6502运行以来所经过的时钟周期总数
unsigned int total_cycles;
// A table for the test
const unsigned char byTestTable[256] =
{
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
};
/*-----------------------------------------------------------------*/
/* Mapper Function */
/*-----------------------------------------------------------------*/
/* The address of 8Kbytes unit of the ROM */
//#define ROMPAGE(a) (ROM + (a) * 0x2000)
#define ROMPAGE(a) (ROM + ((a) << 13))
/* The address of 1Kbytes unit of the VROM */
//#define VROMPAGE(a) (VROM + (a) * 0x400)
#define VROMPAGE(a) (VROM + ((a) << 10))
/*******************************************************************
* 函数名称: MapperWrite *
* 创建人员: 李政 *
* 函数版本: 1.00 *
* 创建日期: 2005/05/08 08:00:00 *
* 功能描述: MMC切换函数,目前支持mapper0、2、3 *
* 入口参数: unsigned short wAddr 向6502RAM写入的地址 *
* unsigned char byData 向6502RAM写入的数据 *
* 返回值 : 无 *
* 修改记录: *
*******************************************************************/
void (*MapperWrite)(unsigned short wAddr, unsigned char byData);
/*******************************************************************
* 函数名称: Map0_Write *
* 创建人员: 李政 *
* 函数版本: 1.00 *
* 创建日期: 2005/05/08 08:00:00 *
* 功能描述: mapper0的MMC切换函数 *
* 入口参数: unsigned short wAddr 向6502RAM写入的地址 *
* unsigned char byData 向6502RAM写入的数据 *
* 返回值 : 无 *
* 修改记录: *
*******************************************************************/
void Map0_Write(unsigned short wAddr, unsigned char byData)
{
#ifndef ONLY_BIN
if (!(wAddr >> 15))
SRAM[wAddr & 0x1fff] = byData;
#endif /* ONLY_BIN */
}
/*******************************************************************
* 函数名称: Map2_Write *
* 创建人员: 李政 *
* 函数版本: 1.00 *
* 创建日期: 2005/05/08 08:00:00 *
* 功能描述: mapper2的MMC切换函数 *
* 入口参数: unsigned short wAddr 向6502RAM写入的地址 *
* unsigned char byData 向6502RAM写入的数据 *
* 返回值 : 无 *
* 修改记录: *
*******************************************************************/
void Map2_Write(unsigned short wAddr, unsigned char byData)
{
#ifndef ONLY_BIN
if (wAddr >> 15)
{
#endif /* ONLY_BIN */
/* Set ROM Banks */
ROMBANK0 = ROM + (byData << 14);
ROMBANK1 = ROMBANK0 + 0x2000;
// 这里- 0x8000是为了在encodePC中不用再做& 0x1FFF的运算了
memmap_tbl[4] = ROMBANK0 - 0x8000;
memmap_tbl[5] = ROMBANK1 - 0xA000;
#ifndef ONLY_BIN
}
else
SRAM[wAddr & 0x1fff] = byData;
#endif /* ONLY_BIN */
}
/*******************************************************************
* 函数名称: Map3_Write *
* 创建人员: 李政 *
* 函数版本: 1.00 *
* 创建日期: 2005/05/08 08:00:00 *
* 功能描述: mapper3的MMC切换函数 *
* 入口参数: unsigned short wAddr 向6502RAM写入的地址 *
* unsigned char byData 向6502RAM写入的数据 *
* 返回值 : 无 *
* 修改记录: *
*******************************************************************/
void Map3_Write(unsigned short wAddr, unsigned char byData)
{
int Base;
/* Set PPU Banks */
Base = ((int)byData << 3) & VRomMask;
PPUBANK[0] = VROMPAGE(Base++);
PPUBANK[1] = VROMPAGE(Base++);
PPUBANK[2] = VROMPAGE(Base++);
PPUBANK[3] = VROMPAGE(Base++);
PPUBANK[4] = VROMPAGE(Base++);
PPUBANK[5] = VROMPAGE(Base++);
PPUBANK[6] = VROMPAGE(Base++);
PPUBANK[7] = VROMPAGE(Base++);
NES_ChrGen = PPUBANK[(PPU_R0 & R0_BG_ADDR) >> 2];
NES_SprGen = PPUBANK[(PPU_R0 & R0_SP_ADDR) >> 1];
}
#ifndef ONLY_BIN
/*******************************************************************
* 函数名称: Map1_Write *
* 创建人员: 李政 *
* 函数版本: 1.00 *
* 创建日期: 2005/05/11 08:43:52 *
* 功能描述: mapper1的MMC切换函数 *
* 入口参数: unsigned short wAddr 向6502RAM写入的地址 *
* unsigned char byData 向6502RAM写入的数据 *
* 返回值 : 无 *
* 修改记录: *
*******************************************************************/
unsigned char Map1_Regs[4];
unsigned int Map1_Cnt;
unsigned char Map1_Latch;
unsigned int Map1_Last_Write_Addr;
enum Map1_Size_t
{
Map1_SMALL,
Map1_512K,
Map1_1024K
};
unsigned int Map1_Size;
unsigned int Map1_256K_base;
unsigned int Map1_swap;
// these are the 4 ROM banks currently selected
unsigned int Map1_bank1;
unsigned int Map1_bank2;
unsigned int Map1_bank3;
unsigned int Map1_bank4;
unsigned int Map1_HI1;
unsigned int Map1_HI2;
void Map1_set_ROM_banks()
{
nes_pc -= (unsigned int)lastbank;
ROMBANK0 = ROMPAGE(((Map1_256K_base << 5) + (Map1_bank1 & /*((256/8)-1)*/31)) & RomMask);
ROMBANK1 = ROMPAGE(((Map1_256K_base << 5) + (Map1_bank2 & /*((256/8)-1)*/31)) & RomMask);
ROMBANK2 = ROMPAGE(((Map1_256K_base << 5) + (Map1_bank3 & /*((256/8)-1)*/31)) & RomMask);
ROMBANK3 = ROMPAGE(((Map1_256K_base << 5) + (Map1_bank4 & /*((256/8)-1)*/31)) & RomMask);
// 这里- 0x8000是为了在encodePC中不用再做& 0x1FFF的运算了
memmap_tbl[4] = ROMBANK0 - 0x8000;
memmap_tbl[5] = ROMBANK1 - 0xA000;
memmap_tbl[6] = ROMBANK2 - 0xC000;
memmap_tbl[7] = ROMBANK3 - 0xE000;
encodePC;
}
/* The address of 1Kbytes unit of the CRAM */
//#define CRAMPAGE(a) &PTRAM[((a)&0x1F) * 0x400]
#define CRAMPAGE(a) &PTRAM[((a)&0x1F) << 10]
void Map1_Write(unsigned short wAddr, unsigned char byData)
{
unsigned int dwRegNum;
if (wAddr >> 15)
{
// if write is to a different reg, reset
if ((wAddr & 0x6000) != (Map1_Last_Write_Addr & 0x6000))
{
Map1_Cnt = 0;
Map1_Latch = 0x00;
}
Map1_Last_Write_Addr = wAddr;
// if bit 7 set, reset and return
if (byData & 0x80)
{
Map1_Cnt = 0;
Map1_Latch = 0x00;
return;
}
if (byData & 0x01) Map1_Latch |= (1 << Map1_Cnt);
Map1_Cnt++;
if (Map1_Cnt < 5) return;
dwRegNum = (wAddr & 0x7FFF) >> 13;
Map1_Regs[dwRegNum] = Map1_Latch;
Map1_Cnt = 0;
Map1_Latch = 0x00;
switch(dwRegNum)
{
case 0:
{
// set mirroring
if (Map1_Regs[0] & 0x02)
{
if (Map1_Regs[0] & 0x01)
{
PPU_Mirroring(0);
}
else
{
PPU_Mirroring(1);
}
}
else
{
// one-screen mirroring
if (Map1_Regs[0] & 0x01)
{
PPU_Mirroring(2);
}
else
{
PPU_Mirroring(3);
}
}
}
break;
case 1:
{
unsigned char byBankNum = Map1_Regs[1];
if (Map1_Size == Map1_1024K)
{
if (Map1_Regs[0] & 0x10)
{
if (Map1_swap)
{
Map1_256K_base = (Map1_Regs[1] & 0x10) >> 4;
if (Map1_Regs[0] & 0x08)
{
Map1_256K_base |= ((Map1_Regs[2] & 0x10) >> 3);
}
Map1_set_ROM_banks();
Map1_swap = 0;
}
else
{
Map1_swap = 1;
}
}
else
{
// use 1st or 4th 256K banks
Map1_256K_base = (Map1_Regs[1] & 0x10) ? 3 : 0;
Map1_set_ROM_banks();
}
}
else if ((Map1_Size == Map1_512K) && (!VRomSize))
{
Map1_256K_base = (Map1_Regs[1] & 0x10) >> 4;
Map1_set_ROM_banks();
}
else if (VRomSize)
{
// set VROM bank at $0000
if (Map1_Regs[0] & 0x10)
{
// swap 4K
byBankNum <<= 2;
byBankNum &= VRomMask;
PPUBANK[0] = VROMPAGE(byBankNum++);
PPUBANK[1] = VROMPAGE(byBankNum++);
PPUBANK[2] = VROMPAGE(byBankNum++);
PPUBANK[3] = VROMPAGE(byBankNum++);
}
else
{
// swap 8K
byBankNum <<= 2;
byBankNum &= VRomMask;
PPUBANK[0] = VROMPAGE(byBankNum++);
PPUBANK[1] = VROMPAGE(byBankNum++);
PPUBANK[2] = VROMPAGE(byBankNum++);
PPUBANK[3] = VROMPAGE(byBankNum++);
PPUBANK[4] = VROMPAGE(byBankNum++);
PPUBANK[5] = VROMPAGE(byBankNum++);
PPUBANK[6] = VROMPAGE(byBankNum++);
PPUBANK[7] = VROMPAGE(byBankNum++);
}
NES_ChrGen = PPUBANK[(PPU_R0 & R0_BG_ADDR) >> 2];
NES_SprGen = PPUBANK[(PPU_R0 & R0_SP_ADDR) >> 1];
}
}
break;
case 2:
{
unsigned char byBankNum = Map1_Regs[2];
if ((Map1_Size == Map1_1024K) && (Map1_Regs[0] & 0x08))
{
if (Map1_swap)
{
Map1_256K_base = (Map1_Regs[1] & 0x10) >> 4;
Map1_256K_base |= ((Map1_Regs[2] & 0x10) >> 3);
Map1_set_ROM_banks();
Map1_swap = 0;
}
else
{
Map1_swap = 1;
}
}
if (!VRomSize)
{
if (Map1_Regs[0] & 0x10)
{
byBankNum <<= 2;
PPUBANK[4] = CRAMPAGE(byBankNum++);
PPUBANK[5] = CRAMPAGE(byBankNum++);
PPUBANK[6] = CRAMPAGE(byBankNum++);
PPUBANK[7] = CRAMPAGE(byBankNum++);
NES_ChrGen = PPUBANK[(PPU_R0 & R0_BG_ADDR) >> 2];
NES_SprGen = PPUBANK[(PPU_R0 & R0_SP_ADDR) >> 1];
break;
}
}
// set 4K VROM bank at $1000
if (Map1_Regs[0] & 0x10)
{
// swap 4K
byBankNum <<= 2;
byBankNum &= VRomMask;
PPUBANK[4] = VROMPAGE(byBankNum++);
PPUBANK[5] = VROMPAGE(byBankNum++);
PPUBANK[6] = VROMPAGE(byBankNum++);
PPUBANK[7] = VROMPAGE(byBankNum++);
NES_ChrGen = PPUBANK[(PPU_R0 & R0_BG_ADDR) >> 2];
NES_SprGen = PPUBANK[(PPU_R0 & R0_SP_ADDR) >> 1];
}
}
break;
case 3:
{
unsigned char byBankNum = Map1_Regs[3];
// set ROM bank
if (Map1_Regs[0] & 0x08)
{
// 16K of ROM
byBankNum <<= 1;
if (Map1_Regs[0] & 0x04)
{
// 16K of ROM at $8000
Map1_bank1 = byBankNum;
Map1_bank2 = byBankNum+1;
Map1_bank3 = Map1_HI1;
Map1_bank4 = Map1_HI2;
}
else
{
// 16K of ROM at $C000
if (Map1_Size == Map1_SMALL)
{
Map1_bank1 = 0;
Map1_bank2 = 1;
Map1_bank3 = byBankNum;
Map1_bank4 = byBankNum+1;
}
}
}
else
{
// 32K of ROM at $8000
byBankNum <<= 1;
Map1_bank1 = byBankNum;
Map1_bank2 = byBankNum+1;
if (Map1_Size == Map1_SMALL)
{
Map1_bank3 = byBankNum+2;
Map1_bank4 = byBankNum+3;
}
}
Map1_set_ROM_banks();
}
break;
}
}
else
SRAM[wAddr & 0x1fff] = byData;
}
/*******************************************************************
* 函数名称: Map7_Write *
* 创建人员: 李政 *
* 函数版本: 1.00 *
* 创建日期: 2005/05/11 08:43:52 *
* 功能描述: mapper7的MMC切换函数 *
* 入口参数: unsigned short wAddr 向6502RAM写入的地址 *
* unsigned char byData 向6502RAM写入的数据 *
* 返回值 : 无 *
* 修改记录: *
*******************************************************************/
void Map7_Write(unsigned short wAddr, unsigned char byData)
{
int Base;
if (wAddr >> 15)
{
/* Set ROM Banks */
Base = (byData & 0x07) << 2;
Base &= RomMask;
nes_pc -= (unsigned int)lastbank;
ROMBANK0 = ROMPAGE(Base++);
ROMBANK1 = ROMPAGE(Base++);
ROMBANK2 = ROMPAGE(Base++);
ROMBANK3 = ROMPAGE(Base++);
// 这里- 0x8000是为了在encodePC中不用再做& 0x1FFF的运算了
memmap_tbl[4] = ROMBANK0 - 0x8000;
memmap_tbl[5] = ROMBANK1 - 0xA000;
memmap_tbl[6] = ROMBANK2 - 0xC000;
memmap_tbl[7] = ROMBANK3 - 0xE000;
encodePC;
/* Name Table Mirroring */
PPU_Mirroring( byData & 0x10 ? 2 : 3 );
}
else
SRAM[wAddr & 0x1fff] = byData;
}
/*******************************************************************
* 函数名称: Map11_Write *
* 创建人员: 李政 *
* 函数版本: 1.00 *
* 创建日期: 2005/05/11 08:43:52 *
* 功能描述: mapper11的MMC切换函数 *
* 入口参数: unsigned short wAddr 向6502RAM写入的地址 *
* unsigned char byData 向6502RAM写入的数据 *
* 返回值 : 无 *
* 修改记录: *
*******************************************************************/
void Map11_Write(unsigned short wAddr, unsigned char byData)
{
int Base;
if (wAddr >> 15)
{
nes_pc -= (unsigned int)lastbank;
/* Set ROM Banks */
Base = byData << 2;
Base &= RomMask;
ROMBANK0 = ROMPAGE(Base++);
ROMBANK1 = ROMPAGE(Base++);
ROMBANK2 = ROMPAGE(Base++);
ROMBANK3 = ROMPAGE(Base++);
// 这里- 0x8000是为了在encodePC中不用再做& 0x1FFF的运算了
memmap_tbl[4] = ROMBANK0 - 0x8000;
memmap_tbl[5] = ROMBANK1 - 0xA000;
memmap_tbl[6] = ROMBANK2 - 0xC000;
memmap_tbl[7] = ROMBANK3 - 0xE000;
encodePC;
if (VRomSize)
{
/* Set PPU Banks */
Base = (byData >> 4) << 3;
Base &= VRomMask;
PPUBANK[0] = VROMPAGE(Base++);
PPUBANK[1] = VROMPAGE(Base++);
PPUBANK[2] = VROMPAGE(Base++);
PPUBANK[3] = VROMPAGE(Base++);
PPUBANK[4] = VROMPAGE(Base++);
PPUBANK[5] = VROMPAGE(Base++);
PPUBANK[6] = VROMPAGE(Base++);
PPUBANK[7] = VROMPAGE(Base++);
NES_ChrGen = PPUBANK[(PPU_R0 & R0_BG_ADDR) >> 2];
NES_SprGen = PPUBANK[(PPU_R0 & R0_SP_ADDR) >> 1];
}
}
else
SRAM[wAddr & 0x1fff] = byData;
}
#endif /* ONLY_BIN */
/*******************************************************************
* 函数名称: CPU_Reset *
* 创建人员: 李政 *
* 函数版本: 1.00 *
* 创建日期: 2005/05/08 08:00:00 *
* 功能描述: 初始化与6502相关的各个参数 *
* 入口参数: 无 *
* 返回值 : 无 *
* 修改记录: *
*******************************************************************/
void CPU_Reset()
{
// Initialize Mapper
int nPage;