1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2005-2006 Forgotten and the VBA development team
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include "GBAinline.h"
42 #include "prof/prof.h"
45 #define UPDATE_REG(address, value)\
47 WRITE16LE(((u16 *)&ioMem[address]),value);\
50 #define ARM_PREFETCH \
52 cpuPrefetch[0] = CPUReadMemoryQuick(armNextPC);\
53 cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);\
56 #define THUMB_PREFETCH \
58 cpuPrefetch[0] = CPUReadHalfWordQuick(armNextPC);\
59 cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);\
62 #define ARM_PREFETCH_NEXT \
63 cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);
65 #define THUMB_PREFETCH_NEXT\
66 cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);
69 #define _stricmp strcasecmp
78 int layerEnableDelay
= 0;
79 bool busPrefetch
= false;
80 bool busPrefetchEnable
= false;
81 u32 busPrefetchCount
= 0;
82 int cpuDmaTicksToUpdate
= 0;
84 bool cpuDmaHack
= false;
88 bool cpuBreakLoop
= false;
91 int gbaSaveType
= 0; // used to remember the save type on reset
92 bool intState
= false;
93 bool stopState
= false;
94 bool holdState
= false;
96 bool cpuSramEnabled
= true;
97 bool cpuFlashEnabled
= true;
98 bool cpuEEPROMEnabled
= true;
99 bool cpuEEPROMSensorEnabled
= false;
103 int cpuTotalTicks
= 0;
105 int profilingTicks
= 0;
106 int profilingTicksReload
= 0;
107 static profile_segment
*profilSegment
= NULL
;
111 u8 freezeWorkRAM
[0x40000];
112 u8 freezeInternalRAM
[0x8000];
113 u8 freezeVRAM
[0x18000];
114 u8 freezePRAM
[0x400];
119 int lcdTicks
= (useBios
&& !skipBios
) ? 1008 : 208;
120 u8 timerOnOffDelay
= 0;
122 bool timer0On
= false;
124 int timer0Reload
= 0;
125 int timer0ClockReload
= 0;
127 bool timer1On
= false;
129 int timer1Reload
= 0;
130 int timer1ClockReload
= 0;
132 bool timer2On
= false;
134 int timer2Reload
= 0;
135 int timer2ClockReload
= 0;
137 bool timer3On
= false;
139 int timer3Reload
= 0;
140 int timer3ClockReload
= 0;
149 void (*cpuSaveGameFunc
)(u32
,u8
) = flashSaveDecide
;
150 void (*renderLine
)() = mode0RenderLine
;
152 bool windowOn
= false;
160 int capturePrevious
= 0;
161 int captureNumber
= 0;
163 const int TIMER_TICKS
[4] = {
170 const u32 objTilesAddress
[3] = {0x010000, 0x014000, 0x014000};
171 const u8 gamepakRamWaitState
[4] = { 4, 3, 2, 8 };
172 const u8 gamepakWaitState
[4] = { 4, 3, 2, 8 };
173 const u8 gamepakWaitState0
[2] = { 2, 1 };
174 const u8 gamepakWaitState1
[2] = { 4, 1 };
175 const u8 gamepakWaitState2
[2] = { 8, 1 };
176 const bool isInRom
[16]=
177 { false, false, false, false, false, false, false, false,
178 true, true, true, true, true, true, false, false };
181 { 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0 };
182 u8 memoryWait32
[16] =
183 { 0, 0, 5, 0, 0, 1, 1, 0, 7, 7, 9, 9, 13, 13, 4, 0 };
184 u8 memoryWaitSeq
[16] =
185 { 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 4, 4, 8, 8, 4, 0 };
186 u8 memoryWaitSeq32
[16] =
187 { 0, 0, 5, 0, 0, 1, 1, 0, 5, 5, 9, 9, 17, 17, 4, 0 };
189 // The videoMemoryWait constants are used to add some waitstates
190 // if the opcode access video memory data outside of vblank/hblank
191 // It seems to happen on only one ticks for each pixel.
192 // Not used for now (too problematic with current code).
193 //const u8 videoMemoryWait[16] =
194 // {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
199 #ifdef WORDS_BIGENDIAN
200 bool cpuBiosSwapped
= false;
379 variable_desc saveGameStruct
[] = {
380 { &DISPCNT
, sizeof(u16
) },
381 { &DISPSTAT
, sizeof(u16
) },
382 { &VCOUNT
, sizeof(u16
) },
383 { &BG0CNT
, sizeof(u16
) },
384 { &BG1CNT
, sizeof(u16
) },
385 { &BG2CNT
, sizeof(u16
) },
386 { &BG3CNT
, sizeof(u16
) },
387 { &BG0HOFS
, sizeof(u16
) },
388 { &BG0VOFS
, sizeof(u16
) },
389 { &BG1HOFS
, sizeof(u16
) },
390 { &BG1VOFS
, sizeof(u16
) },
391 { &BG2HOFS
, sizeof(u16
) },
392 { &BG2VOFS
, sizeof(u16
) },
393 { &BG3HOFS
, sizeof(u16
) },
394 { &BG3VOFS
, sizeof(u16
) },
395 { &BG2PA
, sizeof(u16
) },
396 { &BG2PB
, sizeof(u16
) },
397 { &BG2PC
, sizeof(u16
) },
398 { &BG2PD
, sizeof(u16
) },
399 { &BG2X_L
, sizeof(u16
) },
400 { &BG2X_H
, sizeof(u16
) },
401 { &BG2Y_L
, sizeof(u16
) },
402 { &BG2Y_H
, sizeof(u16
) },
403 { &BG3PA
, sizeof(u16
) },
404 { &BG3PB
, sizeof(u16
) },
405 { &BG3PC
, sizeof(u16
) },
406 { &BG3PD
, sizeof(u16
) },
407 { &BG3X_L
, sizeof(u16
) },
408 { &BG3X_H
, sizeof(u16
) },
409 { &BG3Y_L
, sizeof(u16
) },
410 { &BG3Y_H
, sizeof(u16
) },
411 { &WIN0H
, sizeof(u16
) },
412 { &WIN1H
, sizeof(u16
) },
413 { &WIN0V
, sizeof(u16
) },
414 { &WIN1V
, sizeof(u16
) },
415 { &WININ
, sizeof(u16
) },
416 { &WINOUT
, sizeof(u16
) },
417 { &MOSAIC
, sizeof(u16
) },
418 { &BLDMOD
, sizeof(u16
) },
419 { &COLEV
, sizeof(u16
) },
420 { &COLY
, sizeof(u16
) },
421 { &DM0SAD_L
, sizeof(u16
) },
422 { &DM0SAD_H
, sizeof(u16
) },
423 { &DM0DAD_L
, sizeof(u16
) },
424 { &DM0DAD_H
, sizeof(u16
) },
425 { &DM0CNT_L
, sizeof(u16
) },
426 { &DM0CNT_H
, sizeof(u16
) },
427 { &DM1SAD_L
, sizeof(u16
) },
428 { &DM1SAD_H
, sizeof(u16
) },
429 { &DM1DAD_L
, sizeof(u16
) },
430 { &DM1DAD_H
, sizeof(u16
) },
431 { &DM1CNT_L
, sizeof(u16
) },
432 { &DM1CNT_H
, sizeof(u16
) },
433 { &DM2SAD_L
, sizeof(u16
) },
434 { &DM2SAD_H
, sizeof(u16
) },
435 { &DM2DAD_L
, sizeof(u16
) },
436 { &DM2DAD_H
, sizeof(u16
) },
437 { &DM2CNT_L
, sizeof(u16
) },
438 { &DM2CNT_H
, sizeof(u16
) },
439 { &DM3SAD_L
, sizeof(u16
) },
440 { &DM3SAD_H
, sizeof(u16
) },
441 { &DM3DAD_L
, sizeof(u16
) },
442 { &DM3DAD_H
, sizeof(u16
) },
443 { &DM3CNT_L
, sizeof(u16
) },
444 { &DM3CNT_H
, sizeof(u16
) },
445 { &TM0D
, sizeof(u16
) },
446 { &TM0CNT
, sizeof(u16
) },
447 { &TM1D
, sizeof(u16
) },
448 { &TM1CNT
, sizeof(u16
) },
449 { &TM2D
, sizeof(u16
) },
450 { &TM2CNT
, sizeof(u16
) },
451 { &TM3D
, sizeof(u16
) },
452 { &TM3CNT
, sizeof(u16
) },
453 { &P1
, sizeof(u16
) },
454 { &IE
, sizeof(u16
) },
455 { &IF
, sizeof(u16
) },
456 { &IME
, sizeof(u16
) },
457 { &holdState
, sizeof(bool) },
458 { &holdType
, sizeof(int) },
459 { &lcdTicks
, sizeof(int) },
460 { &timer0On
, sizeof(bool) },
461 { &timer0Ticks
, sizeof(int) },
462 { &timer0Reload
, sizeof(int) },
463 { &timer0ClockReload
, sizeof(int) },
464 { &timer1On
, sizeof(bool) },
465 { &timer1Ticks
, sizeof(int) },
466 { &timer1Reload
, sizeof(int) },
467 { &timer1ClockReload
, sizeof(int) },
468 { &timer2On
, sizeof(bool) },
469 { &timer2Ticks
, sizeof(int) },
470 { &timer2Reload
, sizeof(int) },
471 { &timer2ClockReload
, sizeof(int) },
472 { &timer3On
, sizeof(bool) },
473 { &timer3Ticks
, sizeof(int) },
474 { &timer3Reload
, sizeof(int) },
475 { &timer3ClockReload
, sizeof(int) },
476 { &dma0Source
, sizeof(u32
) },
477 { &dma0Dest
, sizeof(u32
) },
478 { &dma1Source
, sizeof(u32
) },
479 { &dma1Dest
, sizeof(u32
) },
480 { &dma2Source
, sizeof(u32
) },
481 { &dma2Dest
, sizeof(u32
) },
482 { &dma3Source
, sizeof(u32
) },
483 { &dma3Dest
, sizeof(u32
) },
484 { &fxOn
, sizeof(bool) },
485 { &windowOn
, sizeof(bool) },
486 { &N_FLAG
, sizeof(bool) },
487 { &C_FLAG
, sizeof(bool) },
488 { &Z_FLAG
, sizeof(bool) },
489 { &V_FLAG
, sizeof(bool) },
490 { &armState
, sizeof(bool) },
491 { &armIrqEnable
, sizeof(bool) },
492 { &armNextPC
, sizeof(u32
) },
493 { &armMode
, sizeof(int) },
494 { &saveType
, sizeof(int) },
498 static int romSize
= 0x2000000;
501 void cpuProfil(profile_segment
*seg
)
506 void cpuEnableProfiling(int hz
)
510 profilingTicks
= profilingTicksReload
= 16777216 / hz
;
516 // Waitstates when accessing data
517 inline int dataTicksAccess16(u32 address
) // DATA 8/16bits NON SEQ
519 int addr
= (address
>>24)&15;
520 int value
= memoryWait
[addr
];
522 if ((addr
>=0x08) || (addr
< 0x02))
527 else if (busPrefetch
)
529 int waitState
= value
;
532 busPrefetchCount
= ((++busPrefetchCount
)<<waitState
) - 1;
538 inline int dataTicksAccess32(u32 address
) // DATA 32bits NON SEQ
540 int addr
= (address
>>24)&15;
541 int value
= memoryWait32
[addr
];
543 if ((addr
>=0x08) || (addr
< 0x02))
548 else if (busPrefetch
)
550 int waitState
= value
;
553 busPrefetchCount
= ((++busPrefetchCount
)<<waitState
) - 1;
559 inline int dataTicksAccessSeq16(u32 address
)// DATA 8/16bits SEQ
561 int addr
= (address
>>24)&15;
562 int value
= memoryWaitSeq
[addr
];
564 if ((addr
>=0x08) || (addr
< 0x02))
569 else if (busPrefetch
)
571 int waitState
= value
;
574 busPrefetchCount
= ((++busPrefetchCount
)<<waitState
) - 1;
580 inline int dataTicksAccessSeq32(u32 address
)// DATA 32bits SEQ
582 int addr
= (address
>>24)&15;
583 int value
= memoryWaitSeq32
[addr
];
585 if ((addr
>=0x08) || (addr
< 0x02))
590 else if (busPrefetch
)
592 int waitState
= value
;
595 busPrefetchCount
= ((++busPrefetchCount
)<<waitState
) - 1;
602 // Waitstates when executing opcode
603 inline int codeTicksAccess16(u32 address
) // THUMB NON SEQ
605 int addr
= (address
>>24)&15;
607 if ((addr
>=0x08) && (addr
<=0x0D))
609 if (busPrefetchCount
&0x1)
611 if (busPrefetchCount
&0x2)
613 busPrefetchCount
= ((busPrefetchCount
&0xFF)>>2) | (busPrefetchCount
&0xFFFFFF00);
616 busPrefetchCount
= ((busPrefetchCount
&0xFF)>>1) | (busPrefetchCount
&0xFFFFFF00);
617 return memoryWaitSeq
[addr
]-1;
622 return memoryWait
[addr
];
627 busPrefetchCount
= 0;
628 return memoryWait
[addr
];
632 inline int codeTicksAccess32(u32 address
) // ARM NON SEQ
634 int addr
= (address
>>24)&15;
636 if ((addr
>=0x08) && (addr
<=0x0D))
638 if (busPrefetchCount
&0x1)
640 if (busPrefetchCount
&0x2)
642 busPrefetchCount
= ((busPrefetchCount
&0xFF)>>2) | (busPrefetchCount
&0xFFFFFF00);
645 busPrefetchCount
= ((busPrefetchCount
&0xFF)>>1) | (busPrefetchCount
&0xFFFFFF00);
646 return memoryWaitSeq
[addr
] - 1;
650 busPrefetchCount
= 0;
651 return memoryWait32
[addr
];
656 busPrefetchCount
= 0;
657 return memoryWait32
[addr
];
661 inline int codeTicksAccessSeq16(u32 address
) // THUMB SEQ
663 int addr
= (address
>>24)&15;
665 if ((addr
>=0x08) && (addr
<=0x0D))
667 if (busPrefetchCount
&0x1)
669 busPrefetchCount
= ((busPrefetchCount
&0xFF)>>1) | (busPrefetchCount
&0xFFFFFF00);
673 if (busPrefetchCount
>0xFF)
676 return memoryWait
[addr
];
679 return memoryWaitSeq
[addr
];
683 busPrefetchCount
= 0;
684 return memoryWaitSeq
[addr
];
688 inline int codeTicksAccessSeq32(u32 address
) // ARM SEQ
690 int addr
= (address
>>24)&15;
692 if ((addr
>=0x08) && (addr
<=0x0D))
694 if (busPrefetchCount
&0x1)
696 if (busPrefetchCount
&0x2)
698 busPrefetchCount
= ((busPrefetchCount
&0xFF)>>2) | (busPrefetchCount
&0xFFFFFF00);
701 busPrefetchCount
= ((busPrefetchCount
&0xFF)>>1) | (busPrefetchCount
&0xFFFFFF00);
702 return memoryWaitSeq
[addr
];
705 if (busPrefetchCount
>0xFF)
708 return memoryWait32
[addr
];
711 return memoryWaitSeq32
[addr
];
715 return memoryWaitSeq32
[addr
];
720 inline int CPUUpdateTicks()
722 int cpuLoopTicks
= lcdTicks
;
724 if(soundTicks
< cpuLoopTicks
)
725 cpuLoopTicks
= soundTicks
;
727 if(timer0On
&& (timer0Ticks
< cpuLoopTicks
)) {
728 cpuLoopTicks
= timer0Ticks
;
730 if(timer1On
&& !(TM1CNT
& 4) && (timer1Ticks
< cpuLoopTicks
)) {
731 cpuLoopTicks
= timer1Ticks
;
733 if(timer2On
&& !(TM2CNT
& 4) && (timer2Ticks
< cpuLoopTicks
)) {
734 cpuLoopTicks
= timer2Ticks
;
736 if(timer3On
&& !(TM3CNT
& 4) && (timer3Ticks
< cpuLoopTicks
)) {
737 cpuLoopTicks
= timer3Ticks
;
740 if(profilingTicksReload
!= 0) {
741 if(profilingTicks
< cpuLoopTicks
) {
742 cpuLoopTicks
= profilingTicks
;
748 if (SWITicks
< cpuLoopTicks
)
749 cpuLoopTicks
= SWITicks
;
753 if (IRQTicks
< cpuLoopTicks
)
754 cpuLoopTicks
= IRQTicks
;
760 void CPUUpdateWindow0()
763 int x01
= WIN0H
& 255;
766 for(int i
= 0; i
< 240; i
++) {
767 gfxInWin0
[i
] = (i
>= x00
&& i
< x01
);
770 for(int i
= 0; i
< 240; i
++) {
771 gfxInWin0
[i
] = (i
>= x00
|| i
< x01
);
776 void CPUUpdateWindow1()
779 int x01
= WIN1H
& 255;
782 for(int i
= 0; i
< 240; i
++) {
783 gfxInWin1
[i
] = (i
>= x00
&& i
< x01
);
786 for(int i
= 0; i
< 240; i
++) {
787 gfxInWin1
[i
] = (i
>= x00
|| i
< x01
);
792 extern u32 line0
[240];
793 extern u32 line1
[240];
794 extern u32 line2
[240];
795 extern u32 line3
[240];
797 #define CLEAR_ARRAY(a) \
800 for(int i = 0; i < 240; i++) {\
801 *array++ = 0x80000000;\
805 void CPUUpdateRenderBuffers(bool force)
807 if(!(layerEnable
& 0x0100) || force
) {
810 if(!(layerEnable
& 0x0200) || force
) {
813 if(!(layerEnable
& 0x0400) || force
) {
816 if(!(layerEnable
& 0x0800) || force
) {
821 static bool CPUWriteState(gzFile gzFile
)
823 utilWriteInt(gzFile
, SAVE_GAME_VERSION
);
825 utilGzWrite(gzFile
, &rom
[0xa0], 16);
827 utilWriteInt(gzFile
, useBios
);
829 utilGzWrite(gzFile
, ®
[0], sizeof(reg
));
831 utilWriteData(gzFile
, saveGameStruct
);
833 // new to version 0.7.1
834 utilWriteInt(gzFile
, stopState
);
835 // new to version 0.8
836 utilWriteInt(gzFile
, IRQTicks
);
838 utilGzWrite(gzFile
, internalRAM
, 0x8000);
839 utilGzWrite(gzFile
, paletteRAM
, 0x400);
840 utilGzWrite(gzFile
, workRAM
, 0x40000);
841 utilGzWrite(gzFile
, vram
, 0x20000);
842 utilGzWrite(gzFile
, oam
, 0x400);
843 utilGzWrite(gzFile
, pix
, 4*241*162);
844 utilGzWrite(gzFile
, ioMem
, 0x400);
846 eepromSaveGame(gzFile
);
847 flashSaveGame(gzFile
);
848 soundSaveGame(gzFile
);
850 cheatsSaveGame(gzFile
);
858 bool CPUWriteState(const char *file
)
860 gzFile gzFile
= utilGzOpen(file
, "wb");
863 systemMessage(MSG_ERROR_CREATING_FILE
, N_("Error creating file %s"), file
);
867 bool res
= CPUWriteState(gzFile
);
874 bool CPUWriteMemState(char *memory
, int available
)
876 gzFile gzFile
= utilMemGzOpen(memory
, available
, "w");
882 bool res
= CPUWriteState(gzFile
);
884 long pos
= utilGzMemTell(gzFile
)+8;
886 if(pos
>= (available
))
894 static bool CPUReadState(gzFile gzFile
)
896 int version
= utilReadInt(gzFile
);
898 if(version
> SAVE_GAME_VERSION
|| version
< SAVE_GAME_VERSION_1
) {
899 systemMessage(MSG_UNSUPPORTED_VBA_SGM
,
900 N_("Unsupported VisualBoyAdvance save game version %d"),
907 utilGzRead(gzFile
, romname
, 16);
909 if(memcmp(&rom
[0xa0], romname
, 16) != 0) {
911 for(int i
= 0; i
< 16; i
++)
914 systemMessage(MSG_CANNOT_LOAD_SGM
, N_("Cannot load save game for %s"), romname
);
918 bool ub
= utilReadInt(gzFile
) ? true : false;
922 systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS
,
923 N_("Save game is not using the BIOS files"));
925 systemMessage(MSG_SAVE_GAME_USING_BIOS
,
926 N_("Save game is using the BIOS file"));
930 utilGzRead(gzFile
, ®
[0], sizeof(reg
));
932 utilReadData(gzFile
, saveGameStruct
);
934 if(version
< SAVE_GAME_VERSION_3
)
937 stopState
= utilReadInt(gzFile
) ? true : false;
939 if(version
< SAVE_GAME_VERSION_4
)
946 IRQTicks
= utilReadInt(gzFile
);
956 utilGzRead(gzFile
, internalRAM
, 0x8000);
957 utilGzRead(gzFile
, paletteRAM
, 0x400);
958 utilGzRead(gzFile
, workRAM
, 0x40000);
959 utilGzRead(gzFile
, vram
, 0x20000);
960 utilGzRead(gzFile
, oam
, 0x400);
961 if(version
< SAVE_GAME_VERSION_6
)
962 utilGzRead(gzFile
, pix
, 4*240*160);
964 utilGzRead(gzFile
, pix
, 4*241*162);
965 utilGzRead(gzFile
, ioMem
, 0x400);
967 eepromReadGame(gzFile
, version
);
968 flashReadGame(gzFile
, version
);
969 soundReadGame(gzFile
, version
);
971 if(version
> SAVE_GAME_VERSION_1
) {
972 cheatsReadGame(gzFile
, version
);
974 if(version
> SAVE_GAME_VERSION_6
) {
978 if(version
<= SAVE_GAME_VERSION_7
) {
980 #define SWAP(a,b,c) \
984 (c) = (temp) & 0xFFFF;
986 SWAP(dma0Source
, DM0SAD_H
, DM0SAD_L
);
987 SWAP(dma0Dest
, DM0DAD_H
, DM0DAD_L
);
988 SWAP(dma1Source
, DM1SAD_H
, DM1SAD_L
);
989 SWAP(dma1Dest
, DM1DAD_H
, DM1DAD_L
);
990 SWAP(dma2Source
, DM2SAD_H
, DM2SAD_L
);
991 SWAP(dma2Dest
, DM2DAD_H
, DM2DAD_L
);
992 SWAP(dma3Source
, DM3SAD_H
, DM3SAD_L
);
993 SWAP(dma3Dest
, DM3DAD_H
, DM3DAD_L
);
996 if(version
<= SAVE_GAME_VERSION_8
) {
997 timer0ClockReload
= TIMER_TICKS
[TM0CNT
& 3];
998 timer1ClockReload
= TIMER_TICKS
[TM1CNT
& 3];
999 timer2ClockReload
= TIMER_TICKS
[TM2CNT
& 3];
1000 timer3ClockReload
= TIMER_TICKS
[TM3CNT
& 3];
1002 timer0Ticks
= ((0x10000 - TM0D
) << timer0ClockReload
) - timer0Ticks
;
1003 timer1Ticks
= ((0x10000 - TM1D
) << timer1ClockReload
) - timer1Ticks
;
1004 timer2Ticks
= ((0x10000 - TM2D
) << timer2ClockReload
) - timer2Ticks
;
1005 timer3Ticks
= ((0x10000 - TM3D
) << timer3ClockReload
) - timer3Ticks
;
1009 layerEnable
= layerSettings
& DISPCNT
;
1012 CPUUpdateRenderBuffers(true);
1018 cpuSaveGameFunc
= flashSaveDecide
;
1021 cpuSaveGameFunc
= sramWrite
;
1025 cpuSaveGameFunc
= flashWrite
;
1034 systemMessage(MSG_UNSUPPORTED_SAVE_TYPE
,
1035 N_("Unsupported save type %d"), saveType
);
1041 systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
1048 CPUUpdateRegister(0x204, CPUReadHalfWordQuick(0x4000204));
1053 bool CPUReadMemState(char *memory
, int available
)
1055 gzFile gzFile
= utilMemGzOpen(memory
, available
, "r");
1057 bool res
= CPUReadState(gzFile
);
1059 utilGzClose(gzFile
);
1064 bool CPUReadState(const char * file
)
1066 gzFile gzFile
= utilGzOpen(file
, "rb");
1071 bool res
= CPUReadState(gzFile
);
1073 utilGzClose(gzFile
);
1078 bool CPUExportEepromFile(const char *fileName
)
1081 FILE *file
= fopen(fileName
, "wb");
1084 systemMessage(MSG_ERROR_CREATING_FILE
, N_("Error creating file %s"),
1089 for(int i
= 0; i
< eepromSize
;) {
1090 for(int j
= 0; j
< 8; j
++) {
1091 if(fwrite(&eepromData
[i
+7-j
], 1, 1, file
) != 1) {
1103 bool CPUWriteBatteryFile(const char *fileName
)
1105 if(gbaSaveType
== 0) {
1108 else switch(saveType
) {
1118 if((gbaSaveType
) && (gbaSaveType
!=5)) {
1119 FILE *file
= fopen(fileName
, "wb");
1122 systemMessage(MSG_ERROR_CREATING_FILE
, N_("Error creating file %s"),
1127 // only save if Flash/Sram in use or EEprom in use
1128 if(gbaSaveType
!= 3) {
1129 if(gbaSaveType
== 2) {
1130 if(fwrite(flashSaveMemory
, 1, flashSize
, file
) != (size_t)flashSize
) {
1135 if(fwrite(flashSaveMemory
, 1, 0x10000, file
) != 0x10000) {
1141 if(fwrite(eepromData
, 1, eepromSize
, file
) != (size_t)eepromSize
) {
1151 bool CPUReadGSASnapshot(const char *fileName
)
1154 FILE *file
= fopen(fileName
, "rb");
1157 systemMessage(MSG_CANNOT_OPEN_FILE
, N_("Cannot open file %s"), fileName
);
1161 // check file size to know what we should read
1162 fseek(file
, 0, SEEK_END
);
1164 // long size = ftell(file);
1165 fseek(file
, 0x0, SEEK_SET
);
1166 fread(&i
, 1, 4, file
);
1167 fseek(file
, i
, SEEK_CUR
); // Skip SharkPortSave
1168 fseek(file
, 4, SEEK_CUR
); // skip some sort of flag
1169 fread(&i
, 1, 4, file
); // name length
1170 fseek(file
, i
, SEEK_CUR
); // skip name
1171 fread(&i
, 1, 4, file
); // desc length
1172 fseek(file
, i
, SEEK_CUR
); // skip desc
1173 fread(&i
, 1, 4, file
); // notes length
1174 fseek(file
, i
, SEEK_CUR
); // skip notes
1176 fread(&saveSize
, 1, 4, file
); // read length
1177 saveSize
-= 0x1c; // remove header size
1180 fread(buffer
, 1, 16, file
);
1182 for(i
= 0; i
< 16; i
++)
1185 memcpy(buffer2
, &rom
[0xa0], 16);
1187 for(i
= 0; i
< 16; i
++)
1190 if(memcmp(buffer
, buffer2
, 16)) {
1191 systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR
,
1192 N_("Cannot import snapshot for %s. Current game is %s"),
1198 fseek(file
, 12, SEEK_CUR
); // skip some flags
1199 if(saveSize
>= 65536) {
1200 if(fread(flashSaveMemory
, 1, saveSize
, file
) != (size_t)saveSize
) {
1205 systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE
,
1206 N_("Unsupported snapshot file %s"),
1216 bool CPUWriteGSASnapshot(const char *fileName
,
1221 FILE *file
= fopen(fileName
, "wb");
1224 systemMessage(MSG_CANNOT_OPEN_FILE
, N_("Cannot open file %s"), fileName
);
1230 utilPutDword(buffer
, 0x0d); // SharkPortSave length
1231 fwrite(buffer
, 1, 4, file
);
1232 fwrite("SharkPortSave", 1, 0x0d, file
);
1233 utilPutDword(buffer
, 0x000f0000);
1234 fwrite(buffer
, 1, 4, file
); // save type 0x000f0000 = GBA save
1235 utilPutDword(buffer
, (u32
)strlen(title
));
1236 fwrite(buffer
, 1, 4, file
); // title length
1237 fwrite(title
, 1, strlen(title
), file
);
1238 utilPutDword(buffer
, (u32
)strlen(desc
));
1239 fwrite(buffer
, 1, 4, file
); // desc length
1240 fwrite(desc
, 1, strlen(desc
), file
);
1241 utilPutDword(buffer
, (u32
)strlen(notes
));
1242 fwrite(buffer
, 1, 4, file
); // notes length
1243 fwrite(notes
, 1, strlen(notes
), file
);
1244 int saveSize
= 0x10000;
1245 if(gbaSaveType
== 2)
1246 saveSize
= flashSize
;
1247 int totalSize
= saveSize
+ 0x1c;
1249 utilPutDword(buffer
, totalSize
); // length of remainder of save - CRC
1250 fwrite(buffer
, 1, 4, file
);
1253 memset(temp
, 0, 28);
1254 memcpy(temp
, &rom
[0xa0], 16); // copy internal name
1255 temp
[0x10] = rom
[0xbe]; // reserved area (old checksum)
1256 temp
[0x11] = rom
[0xbf]; // reserved area (old checksum)
1257 temp
[0x12] = rom
[0xbd]; // complement check
1258 temp
[0x13] = rom
[0xb0]; // maker
1259 temp
[0x14] = 1; // 1 save ?
1260 memcpy(&temp
[0x1c], flashSaveMemory
, saveSize
); // copy save
1261 fwrite(temp
, 1, totalSize
, file
); // write save + header
1264 for(int i
= 0; i
< totalSize
; i
++) {
1265 crc
+= ((u32
)temp
[i
] << (crc
% 0x18));
1268 utilPutDword(buffer
, crc
);
1269 fwrite(buffer
, 1, 4, file
); // CRC?
1275 bool CPUImportEepromFile(const char *fileName
)
1277 FILE *file
= fopen(fileName
, "rb");
1282 // check file size to know what we should read
1283 fseek(file
, 0, SEEK_END
);
1285 long size
= ftell(file
);
1286 fseek(file
, 0, SEEK_SET
);
1287 if(size
== 512 || size
== 0x2000) {
1288 if(fread(eepromData
, 1, size
, file
) != (size_t)size
) {
1292 for(int i
= 0; i
< size
;) {
1293 u8 tmp
= eepromData
[i
];
1294 eepromData
[i
] = eepromData
[7-i
];
1295 eepromData
[7-i
] = tmp
;
1297 tmp
= eepromData
[i
];
1298 eepromData
[i
] = eepromData
[7-i
];
1299 eepromData
[7-i
] = tmp
;
1301 tmp
= eepromData
[i
];
1302 eepromData
[i
] = eepromData
[7-i
];
1303 eepromData
[7-i
] = tmp
;
1305 tmp
= eepromData
[i
];
1306 eepromData
[i
] = eepromData
[7-i
];
1307 eepromData
[7-i
] = tmp
;
1317 bool CPUReadBatteryFile(const char *fileName
)
1319 FILE *file
= fopen(fileName
, "rb");
1324 // check file size to know what we should read
1325 fseek(file
, 0, SEEK_END
);
1327 long size
= ftell(file
);
1328 fseek(file
, 0, SEEK_SET
);
1329 systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
1331 if(size
== 512 || size
== 0x2000) {
1332 if(fread(eepromData
, 1, size
, file
) != (size_t)size
) {
1337 if(size
== 0x20000) {
1338 if(fread(flashSaveMemory
, 1, 0x20000, file
) != 0x20000) {
1342 flashSetSize(0x20000);
1344 if(fread(flashSaveMemory
, 1, 0x10000, file
) != 0x10000) {
1348 flashSetSize(0x10000);
1355 bool CPUWritePNGFile(const char *fileName
)
1357 return utilWritePNGFile(fileName
, 240, 160, pix
);
1360 bool CPUWriteBMPFile(const char *fileName
)
1362 return utilWriteBMPFile(fileName
, 240, 160, pix
);
1365 bool CPUIsZipFile(const char * file
)
1367 if(strlen(file
) > 4) {
1368 const char * p
= strrchr(file
,'.');
1371 if(_stricmp(p
, ".zip") == 0)
1379 bool CPUIsGBAImage(const char * file
)
1381 cpuIsMultiBoot
= false;
1382 if(strlen(file
) > 4) {
1383 const char * p
= strrchr(file
,'.');
1386 if(_stricmp(p
, ".gba") == 0)
1388 if(_stricmp(p
, ".agb") == 0)
1390 if(_stricmp(p
, ".bin") == 0)
1392 if(_stricmp(p
, ".elf") == 0)
1394 if(_stricmp(p
, ".mb") == 0) {
1395 cpuIsMultiBoot
= true;
1404 bool CPUIsGBABios(const char * file
)
1406 if(strlen(file
) > 4) {
1407 const char * p
= strrchr(file
,'.');
1410 if(_stricmp(p
, ".gba") == 0)
1412 if(_stricmp(p
, ".agb") == 0)
1414 if(_stricmp(p
, ".bin") == 0)
1416 if(_stricmp(p
, ".bios") == 0)
1424 bool CPUIsELF(const char *file
)
1426 if(strlen(file
) > 4) {
1427 const char * p
= strrchr(file
,'.');
1430 if(_stricmp(p
, ".elf") == 0)
1440 if(profilingTicksReload
) {
1455 if(paletteRAM
!= NULL
) {
1460 if(internalRAM
!= NULL
) {
1465 if(workRAM
!= NULL
) {
1492 systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
1497 int CPULoadRom(const char *szFile
)
1499 romSize
= 0x2000000;
1504 systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
1506 rom
= (u8
*)malloc(0x2000000);
1508 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
1512 workRAM
= (u8
*)calloc(1, 0x40000);
1513 if(workRAM
== NULL
) {
1514 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
1519 u8
*whereToLoad
= rom
;
1521 whereToLoad
= workRAM
;
1523 if(CPUIsELF(szFile
)) {
1524 FILE *f
= fopen(szFile
, "rb");
1526 systemMessage(MSG_ERROR_OPENING_IMAGE
, N_("Error opening image %s"),
1534 bool res
= elfRead(szFile
, romSize
, f
);
1535 if(!res
|| romSize
== 0) {
1543 } else if(!utilLoad(szFile
,
1554 u16
*temp
= (u16
*)(rom
+((romSize
+1)&~1));
1556 for(i
= (romSize
+1)&~1; i
< 0x2000000; i
+=2) {
1557 WRITE16LE(temp
, (i
>> 1) & 0xFFFF);
1561 bios
= (u8
*)calloc(1,0x4000);
1563 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
1568 internalRAM
= (u8
*)calloc(1,0x8000);
1569 if(internalRAM
== NULL
) {
1570 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
1575 paletteRAM
= (u8
*)calloc(1,0x400);
1576 if(paletteRAM
== NULL
) {
1577 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
1582 vram
= (u8
*)calloc(1, 0x20000);
1584 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
1589 oam
= (u8
*)calloc(1, 0x400);
1591 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
1596 pix
= (u8
*)calloc(1, 4 * 241 * 162);
1598 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
1603 ioMem
= (u8
*)calloc(1, 0x400);
1605 systemMessage(MSG_OUT_OF_MEMORY
, N_("Failed to allocate memory for %s"),
1614 CPUUpdateRenderBuffers(true);
1619 void doMirroring (bool b
)
1621 u32 mirroredRomSize
= (((romSize
)>>20) & 0x3F)<<20;
1622 u32 mirroredRomAddress
= romSize
;
1623 if ((mirroredRomSize
<=0x800000) && (b
))
1625 mirroredRomAddress
= mirroredRomSize
;
1626 if (mirroredRomSize
==0)
1627 mirroredRomSize
=0x100000;
1628 while (mirroredRomAddress
<0x01000000)
1630 memcpy ((u16
*)(rom
+mirroredRomAddress
), (u16
*)(rom
), mirroredRomSize
);
1631 mirroredRomAddress
+=mirroredRomSize
;
1636 void CPUUpdateRender()
1638 switch(DISPCNT
& 7) {
1640 if((!fxOn
&& !windowOn
&& !(layerEnable
& 0x8000)) ||
1642 renderLine
= mode0RenderLine
;
1643 else if(fxOn
&& !windowOn
&& !(layerEnable
& 0x8000))
1644 renderLine
= mode0RenderLineNoWindow
;
1646 renderLine
= mode0RenderLineAll
;
1649 if((!fxOn
&& !windowOn
&& !(layerEnable
& 0x8000)) ||
1651 renderLine
= mode1RenderLine
;
1652 else if(fxOn
&& !windowOn
&& !(layerEnable
& 0x8000))
1653 renderLine
= mode1RenderLineNoWindow
;
1655 renderLine
= mode1RenderLineAll
;
1658 if((!fxOn
&& !windowOn
&& !(layerEnable
& 0x8000)) ||
1660 renderLine
= mode2RenderLine
;
1661 else if(fxOn
&& !windowOn
&& !(layerEnable
& 0x8000))
1662 renderLine
= mode2RenderLineNoWindow
;
1664 renderLine
= mode2RenderLineAll
;
1667 if((!fxOn
&& !windowOn
&& !(layerEnable
& 0x8000)) ||
1669 renderLine
= mode3RenderLine
;
1670 else if(fxOn
&& !windowOn
&& !(layerEnable
& 0x8000))
1671 renderLine
= mode3RenderLineNoWindow
;
1673 renderLine
= mode3RenderLineAll
;
1676 if((!fxOn
&& !windowOn
&& !(layerEnable
& 0x8000)) ||
1678 renderLine
= mode4RenderLine
;
1679 else if(fxOn
&& !windowOn
&& !(layerEnable
& 0x8000))
1680 renderLine
= mode4RenderLineNoWindow
;
1682 renderLine
= mode4RenderLineAll
;
1685 if((!fxOn
&& !windowOn
&& !(layerEnable
& 0x8000)) ||
1687 renderLine
= mode5RenderLine
;
1688 else if(fxOn
&& !windowOn
&& !(layerEnable
& 0x8000))
1689 renderLine
= mode5RenderLineNoWindow
;
1691 renderLine
= mode5RenderLineAll
;
1697 void CPUUpdateCPSR()
1699 u32 CPSR
= reg
[16].I
& 0x40;
1712 CPSR
|= (armMode
& 0x1F);
1716 void CPUUpdateFlags(bool breakLoop
)
1718 u32 CPSR
= reg
[16].I
;
1720 N_FLAG
= (CPSR
& 0x80000000) ? true: false;
1721 Z_FLAG
= (CPSR
& 0x40000000) ? true: false;
1722 C_FLAG
= (CPSR
& 0x20000000) ? true: false;
1723 V_FLAG
= (CPSR
& 0x10000000) ? true: false;
1724 armState
= (CPSR
& 0x20) ? false : true;
1725 armIrqEnable
= (CPSR
& 0x80) ? false : true;
1727 if (armIrqEnable
&& (IF
& IE
) && (IME
& 1))
1728 cpuNextEvent
= cpuTotalTicks
;
1732 void CPUUpdateFlags()
1734 CPUUpdateFlags(true);
1737 #ifdef WORDS_BIGENDIAN
1738 static void CPUSwap(volatile u32
*a
, volatile u32
*b
)
1740 volatile u32 c
= *b
;
1745 static void CPUSwap(u32
*a
, u32
*b
)
1753 void CPUSwitchMode(int mode
, bool saveState
, bool breakLoop
)
1755 // if(armMode == mode)
1763 reg
[R13_USR
].I
= reg
[13].I
;
1764 reg
[R14_USR
].I
= reg
[14].I
;
1765 reg
[17].I
= reg
[16].I
;
1768 CPUSwap(®
[R8_FIQ
].I
, ®
[8].I
);
1769 CPUSwap(®
[R9_FIQ
].I
, ®
[9].I
);
1770 CPUSwap(®
[R10_FIQ
].I
, ®
[10].I
);
1771 CPUSwap(®
[R11_FIQ
].I
, ®
[11].I
);
1772 CPUSwap(®
[R12_FIQ
].I
, ®
[12].I
);
1773 reg
[R13_FIQ
].I
= reg
[13].I
;
1774 reg
[R14_FIQ
].I
= reg
[14].I
;
1775 reg
[SPSR_FIQ
].I
= reg
[17].I
;
1778 reg
[R13_IRQ
].I
= reg
[13].I
;
1779 reg
[R14_IRQ
].I
= reg
[14].I
;
1780 reg
[SPSR_IRQ
].I
= reg
[17].I
;
1783 reg
[R13_SVC
].I
= reg
[13].I
;
1784 reg
[R14_SVC
].I
= reg
[14].I
;
1785 reg
[SPSR_SVC
].I
= reg
[17].I
;
1788 reg
[R13_ABT
].I
= reg
[13].I
;
1789 reg
[R14_ABT
].I
= reg
[14].I
;
1790 reg
[SPSR_ABT
].I
= reg
[17].I
;
1793 reg
[R13_UND
].I
= reg
[13].I
;
1794 reg
[R14_UND
].I
= reg
[14].I
;
1795 reg
[SPSR_UND
].I
= reg
[17].I
;
1799 u32 CPSR
= reg
[16].I
;
1800 u32 SPSR
= reg
[17].I
;
1805 reg
[13].I
= reg
[R13_USR
].I
;
1806 reg
[14].I
= reg
[R14_USR
].I
;
1810 CPUSwap(®
[8].I
, ®
[R8_FIQ
].I
);
1811 CPUSwap(®
[9].I
, ®
[R9_FIQ
].I
);
1812 CPUSwap(®
[10].I
, ®
[R10_FIQ
].I
);
1813 CPUSwap(®
[11].I
, ®
[R11_FIQ
].I
);
1814 CPUSwap(®
[12].I
, ®
[R12_FIQ
].I
);
1815 reg
[13].I
= reg
[R13_FIQ
].I
;
1816 reg
[14].I
= reg
[R14_FIQ
].I
;
1820 reg
[17].I
= reg
[SPSR_FIQ
].I
;
1823 reg
[13].I
= reg
[R13_IRQ
].I
;
1824 reg
[14].I
= reg
[R14_IRQ
].I
;
1829 reg
[17].I
= reg
[SPSR_IRQ
].I
;
1832 reg
[13].I
= reg
[R13_SVC
].I
;
1833 reg
[14].I
= reg
[R14_SVC
].I
;
1838 reg
[17].I
= reg
[SPSR_SVC
].I
;
1841 reg
[13].I
= reg
[R13_ABT
].I
;
1842 reg
[14].I
= reg
[R14_ABT
].I
;
1847 reg
[17].I
= reg
[SPSR_ABT
].I
;
1850 reg
[13].I
= reg
[R13_UND
].I
;
1851 reg
[14].I
= reg
[R14_UND
].I
;
1856 reg
[17].I
= reg
[SPSR_UND
].I
;
1859 systemMessage(MSG_UNSUPPORTED_ARM_MODE
, N_("Unsupported ARM mode %02x"), mode
);
1863 CPUUpdateFlags(breakLoop
);
1867 void CPUSwitchMode(int mode
, bool saveState
)
1869 CPUSwitchMode(mode
, saveState
, true);
1872 void CPUUndefinedException()
1875 bool savedArmState
= armState
;
1876 CPUSwitchMode(0x1b, true, false);
1877 reg
[14].I
= PC
- (savedArmState
? 4 : 2);
1880 armIrqEnable
= false;
1886 void CPUSoftwareInterrupt()
1889 bool savedArmState
= armState
;
1890 CPUSwitchMode(0x13, true, false);
1891 reg
[14].I
= PC
- (savedArmState
? 4 : 2);
1894 armIrqEnable
= false;
1900 void CPUSoftwareInterrupt(int comment
)
1902 static bool disableMessage
= false;
1903 if(armState
) comment
>>= 16;
1905 if(comment
== 0xff) {
1906 extern void (*dbgOutput
)(char *, u32
);
1907 dbgOutput(NULL
, reg
[0].I
);
1912 if(comment
== 0xfe) {
1913 profStartup(reg
[0].I
, reg
[1].I
);
1916 if(comment
== 0xfd) {
1917 profControl(reg
[0].I
);
1920 if(comment
== 0xfc) {
1924 if(comment
== 0xfb) {
1929 if(comment
== 0xfa) {
1934 if(comment
== 0xf9) {
1936 cpuNextEvent
= cpuTotalTicks
;
1937 cpuBreakLoop
= true;
1943 if(systemVerbose
& VERBOSE_SWI
) {
1944 log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment
,
1945 armState
? armNextPC
- 4: armNextPC
-2,
1952 CPUSoftwareInterrupt();
1955 // This would be correct, but it causes problems if uncommented
1957 // biosProtected = 0xe3a02004;
1966 BIOS_RegisterRamReset();
1970 if(systemVerbose
& VERBOSE_SWI
) {
1971 log("Halt: (VCOUNT = %2d)\n",
1977 cpuNextEvent
= cpuTotalTicks
;
1981 if(systemVerbose
& VERBOSE_SWI
) {
1982 log("Stop: (VCOUNT = %2d)\n",
1989 cpuNextEvent
= cpuTotalTicks
;
1993 if(systemVerbose
& VERBOSE_SWI
) {
1994 log("IntrWait: 0x%08x,0x%08x (VCOUNT = %2d)\n",
2000 CPUSoftwareInterrupt();
2004 if(systemVerbose
& VERBOSE_SWI
) {
2005 log("VBlankIntrWait: (VCOUNT = %2d)\n",
2009 CPUSoftwareInterrupt();
2012 CPUSoftwareInterrupt();
2015 CPUSoftwareInterrupt();
2028 int len
= (reg
[2].I
& 0x1FFFFF) >>1;
2029 if (!(((reg
[0].I
& 0xe000000) == 0) ||
2030 ((reg
[0].I
+ len
) & 0xe000000) == 0))
2032 if ((reg
[2].I
>> 24) & 1)
2034 if ((reg
[2].I
>> 26) & 1)
2035 SWITicks
= (7 + memoryWait32
[(reg
[1].I
>>24) & 0xF]) * (len
>>1);
2037 SWITicks
= (8 + memoryWait
[(reg
[1].I
>>24) & 0xF]) * (len
);
2041 if ((reg
[2].I
>> 26) & 1)
2042 SWITicks
= (10 + memoryWait32
[(reg
[0].I
>>24) & 0xF] +
2043 memoryWait32
[(reg
[1].I
>>24) & 0xF]) * (len
>>1);
2045 SWITicks
= (11 + memoryWait
[(reg
[0].I
>>24) & 0xF] +
2046 memoryWait
[(reg
[1].I
>>24) & 0xF]) * len
;
2054 int len
= (reg
[2].I
& 0x1FFFFF) >>5;
2055 if (!(((reg
[0].I
& 0xe000000) == 0) ||
2056 ((reg
[0].I
+ len
) & 0xe000000) == 0))
2058 if ((reg
[2].I
>> 24) & 1)
2059 SWITicks
= (6 + memoryWait32
[(reg
[1].I
>>24) & 0xF] +
2060 7 * (memoryWaitSeq32
[(reg
[1].I
>>24) & 0xF] + 1)) * len
;
2062 SWITicks
= (9 + memoryWait32
[(reg
[0].I
>>24) & 0xF] +
2063 memoryWait32
[(reg
[1].I
>>24) & 0xF] +
2064 7 * (memoryWaitSeq32
[(reg
[0].I
>>24) & 0xF] +
2065 memoryWaitSeq32
[(reg
[1].I
>>24) & 0xF] + 2)) * len
;
2071 BIOS_GetBiosChecksum();
2077 BIOS_ObjAffineSet();
2081 int len
= CPUReadHalfWord(reg
[2].I
);
2082 if (!(((reg
[0].I
& 0xe000000) == 0) ||
2083 ((reg
[0].I
+ len
) & 0xe000000) == 0))
2084 SWITicks
= (32 + memoryWait
[(reg
[0].I
>>24) & 0xF]) * len
;
2090 u32 len
= CPUReadMemory(reg
[0].I
) >> 8;
2091 if(!(((reg
[0].I
& 0xe000000) == 0) ||
2092 ((reg
[0].I
+ (len
& 0x1fffff)) & 0xe000000) == 0))
2093 SWITicks
= (9 + memoryWait
[(reg
[1].I
>>24) & 0xF]) * len
;
2095 BIOS_LZ77UnCompWram();
2099 u32 len
= CPUReadMemory(reg
[0].I
) >> 8;
2100 if(!(((reg
[0].I
& 0xe000000) == 0) ||
2101 ((reg
[0].I
+ (len
& 0x1fffff)) & 0xe000000) == 0))
2102 SWITicks
= (19 + memoryWait
[(reg
[1].I
>>24) & 0xF]) * len
;
2104 BIOS_LZ77UnCompVram();
2108 u32 len
= CPUReadMemory(reg
[0].I
) >> 8;
2109 if(!(((reg
[0].I
& 0xe000000) == 0) ||
2110 ((reg
[0].I
+ (len
& 0x1fffff)) & 0xe000000) == 0))
2111 SWITicks
= (29 + (memoryWait
[(reg
[0].I
>>24) & 0xF]<<1)) * len
;
2117 u32 len
= CPUReadMemory(reg
[0].I
) >> 8;
2118 if(!(((reg
[0].I
& 0xe000000) == 0) ||
2119 ((reg
[0].I
+ (len
& 0x1fffff)) & 0xe000000) == 0))
2120 SWITicks
= (11 + memoryWait
[(reg
[0].I
>>24) & 0xF] +
2121 memoryWait
[(reg
[1].I
>>24) & 0xF]) * len
;
2123 BIOS_RLUnCompWram();
2127 u32 len
= CPUReadMemory(reg
[0].I
) >> 9;
2128 if(!(((reg
[0].I
& 0xe000000) == 0) ||
2129 ((reg
[0].I
+ (len
& 0x1fffff)) & 0xe000000) == 0))
2130 SWITicks
= (34 + (memoryWait
[(reg
[0].I
>>24) & 0xF] << 1) +
2131 memoryWait
[(reg
[1].I
>>24) & 0xF]) * len
;
2133 BIOS_RLUnCompVram();
2137 u32 len
= CPUReadMemory(reg
[0].I
) >> 8;
2138 if(!(((reg
[0].I
& 0xe000000) == 0) ||
2139 ((reg
[0].I
+ (len
& 0x1fffff)) & 0xe000000) == 0))
2140 SWITicks
= (13 + memoryWait
[(reg
[0].I
>>24) & 0xF] +
2141 memoryWait
[(reg
[1].I
>>24) & 0xF]) * len
;
2143 BIOS_Diff8bitUnFilterWram();
2147 u32 len
= CPUReadMemory(reg
[0].I
) >> 9;
2148 if(!(((reg
[0].I
& 0xe000000) == 0) ||
2149 ((reg
[0].I
+ (len
& 0x1fffff)) & 0xe000000) == 0))
2150 SWITicks
= (39 + (memoryWait
[(reg
[0].I
>>24) & 0xF]<<1) +
2151 memoryWait
[(reg
[1].I
>>24) & 0xF]) * len
;
2153 BIOS_Diff8bitUnFilterVram();
2157 u32 len
= CPUReadMemory(reg
[0].I
) >> 9;
2158 if(!(((reg
[0].I
& 0xe000000) == 0) ||
2159 ((reg
[0].I
+ (len
& 0x1fffff)) & 0xe000000) == 0))
2160 SWITicks
= (13 + memoryWait
[(reg
[0].I
>>24) & 0xF] +
2161 memoryWait
[(reg
[1].I
>>24) & 0xF]) * len
;
2163 BIOS_Diff16bitUnFilter();
2167 if(systemVerbose
& VERBOSE_SWI
) {
2168 log("SoundBiasSet: 0x%08x (VCOUNT = %2d)\n",
2176 systemSoundResume();
2179 BIOS_MidiKey2Freq();
2182 BIOS_SndDriverJmpTableCopy();
2183 // let it go, because we don't really emulate this function
2186 if(systemVerbose
& VERBOSE_SWI
) {
2187 log("SWI: %08x at %08x (0x%08x,0x%08x,0x%08x,VCOUNT = %2d)\n", comment
,
2188 armState
? armNextPC
- 4: armNextPC
-2,
2196 if(!disableMessage
) {
2197 systemMessage(MSG_UNSUPPORTED_BIOS_FUNCTION
,
2198 N_("Unsupported BIOS function %02x called from %08x. A BIOS file is needed in order to get correct behaviour."),
2200 armMode
? armNextPC
- 4: armNextPC
- 2);
2201 disableMessage
= true;
2207 void CPUCompareVCOUNT()
2209 if(VCOUNT
== (DISPSTAT
>> 8)) {
2211 UPDATE_REG(0x04, DISPSTAT
);
2213 if(DISPSTAT
& 0x20) {
2215 UPDATE_REG(0x202, IF
);
2219 UPDATE_REG(0x4, DISPSTAT
);
2221 if (layerEnableDelay
>0)
2224 if (layerEnableDelay
==1)
2225 layerEnable
= layerSettings
& DISPCNT
;
2230 void doDMA(u32
&s
, u32
&d
, u32 si
, u32 di
, u32 c
, int transfer32
)
2239 // This is done to get the correct waitstates.
2245 //if ((sm>=0x05) && (sm<=0x07) || (dm>=0x05) && (dm <=0x07))
2246 // blank = (((DISPSTAT | ((DISPSTAT>>1)&1))==1) ? true : false);
2250 if(s
< 0x02000000 && (reg
[15].I
>> 24)) {
2252 CPUWriteMemory(d
, 0);
2258 cpuDmaLast
= CPUReadMemory(s
);
2259 CPUWriteMemory(d
, cpuDmaLast
);
2269 if(s
< 0x02000000 && (reg
[15].I
>> 24)) {
2271 CPUWriteHalfWord(d
, 0);
2277 cpuDmaLast
= CPUReadHalfWord(s
);
2278 CPUWriteHalfWord(d
, cpuDmaLast
);
2279 cpuDmaLast
|= (cpuDmaLast
<<16);
2292 sw
=1+memoryWaitSeq32
[sm
& 15];
2293 dw
=1+memoryWaitSeq32
[dm
& 15];
2294 totalTicks
= (sw
+dw
)*(sc
-1) + 6 + memoryWait32
[sm
& 15] +
2295 memoryWaitSeq32
[dm
& 15];
2299 sw
= 1+memoryWaitSeq
[sm
& 15];
2300 dw
= 1+memoryWaitSeq
[dm
& 15];
2301 totalTicks
= (sw
+dw
)*(sc
-1) + 6 + memoryWait
[sm
& 15] +
2302 memoryWaitSeq
[dm
& 15];
2305 cpuDmaTicksToUpdate
+= totalTicks
;
2309 void CPUCheckDMA(int reason
, int dmamask
)
2312 if((DM0CNT_H
& 0x8000) && (dmamask
& 1)) {
2313 if(((DM0CNT_H
>> 12) & 3) == reason
) {
2314 u32 sourceIncrement
= 4;
2315 u32 destIncrement
= 4;
2316 switch((DM0CNT_H
>> 7) & 3) {
2320 sourceIncrement
= (u32
)-4;
2323 sourceIncrement
= 0;
2326 switch((DM0CNT_H
>> 5) & 3) {
2330 destIncrement
= (u32
)-4;
2337 if(systemVerbose
& VERBOSE_DMA0
) {
2338 int count
= (DM0CNT_L
? DM0CNT_L
: 0x4000) << 1;
2339 if(DM0CNT_H
& 0x0400)
2341 log("DMA0: s=%08x d=%08x c=%04x count=%08x\n", dma0Source
, dma0Dest
,
2346 doDMA(dma0Source
, dma0Dest
, sourceIncrement
, destIncrement
,
2347 DM0CNT_L
? DM0CNT_L
: 0x4000,
2351 if(DM0CNT_H
& 0x4000) {
2353 UPDATE_REG(0x202, IF
);
2354 cpuNextEvent
= cpuTotalTicks
;
2357 if(((DM0CNT_H
>> 5) & 3) == 3) {
2358 dma0Dest
= DM0DAD_L
| (DM0DAD_H
<< 16);
2361 if(!(DM0CNT_H
& 0x0200) || (reason
== 0)) {
2363 UPDATE_REG(0xBA, DM0CNT_H
);
2369 if((DM1CNT_H
& 0x8000) && (dmamask
& 2)) {
2370 if(((DM1CNT_H
>> 12) & 3) == reason
) {
2371 u32 sourceIncrement
= 4;
2372 u32 destIncrement
= 4;
2373 switch((DM1CNT_H
>> 7) & 3) {
2377 sourceIncrement
= (u32
)-4;
2380 sourceIncrement
= 0;
2383 switch((DM1CNT_H
>> 5) & 3) {
2387 destIncrement
= (u32
)-4;
2395 if(systemVerbose
& VERBOSE_DMA1
) {
2396 log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source
, dma1Dest
,
2401 doDMA(dma1Source
, dma1Dest
, sourceIncrement
, 0, 4,
2405 if(systemVerbose
& VERBOSE_DMA1
) {
2406 int count
= (DM1CNT_L
? DM1CNT_L
: 0x4000) << 1;
2407 if(DM1CNT_H
& 0x0400)
2409 log("DMA1: s=%08x d=%08x c=%04x count=%08x\n", dma1Source
, dma1Dest
,
2414 doDMA(dma1Source
, dma1Dest
, sourceIncrement
, destIncrement
,
2415 DM1CNT_L
? DM1CNT_L
: 0x4000,
2420 if(DM1CNT_H
& 0x4000) {
2422 UPDATE_REG(0x202, IF
);
2423 cpuNextEvent
= cpuTotalTicks
;
2426 if(((DM1CNT_H
>> 5) & 3) == 3) {
2427 dma1Dest
= DM1DAD_L
| (DM1DAD_H
<< 16);
2430 if(!(DM1CNT_H
& 0x0200) || (reason
== 0)) {
2432 UPDATE_REG(0xC6, DM1CNT_H
);
2438 if((DM2CNT_H
& 0x8000) && (dmamask
& 4)) {
2439 if(((DM2CNT_H
>> 12) & 3) == reason
) {
2440 u32 sourceIncrement
= 4;
2441 u32 destIncrement
= 4;
2442 switch((DM2CNT_H
>> 7) & 3) {
2446 sourceIncrement
= (u32
)-4;
2449 sourceIncrement
= 0;
2452 switch((DM2CNT_H
>> 5) & 3) {
2456 destIncrement
= (u32
)-4;
2464 if(systemVerbose
& VERBOSE_DMA2
) {
2465 int count
= (4) << 2;
2466 log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source
, dma2Dest
,
2471 doDMA(dma2Source
, dma2Dest
, sourceIncrement
, 0, 4,
2475 if(systemVerbose
& VERBOSE_DMA2
) {
2476 int count
= (DM2CNT_L
? DM2CNT_L
: 0x4000) << 1;
2477 if(DM2CNT_H
& 0x0400)
2479 log("DMA2: s=%08x d=%08x c=%04x count=%08x\n", dma2Source
, dma2Dest
,
2484 doDMA(dma2Source
, dma2Dest
, sourceIncrement
, destIncrement
,
2485 DM2CNT_L
? DM2CNT_L
: 0x4000,
2490 if(DM2CNT_H
& 0x4000) {
2492 UPDATE_REG(0x202, IF
);
2493 cpuNextEvent
= cpuTotalTicks
;
2496 if(((DM2CNT_H
>> 5) & 3) == 3) {
2497 dma2Dest
= DM2DAD_L
| (DM2DAD_H
<< 16);
2500 if(!(DM2CNT_H
& 0x0200) || (reason
== 0)) {
2502 UPDATE_REG(0xD2, DM2CNT_H
);
2508 if((DM3CNT_H
& 0x8000) && (dmamask
& 8)) {
2509 if(((DM3CNT_H
>> 12) & 3) == reason
) {
2510 u32 sourceIncrement
= 4;
2511 u32 destIncrement
= 4;
2512 switch((DM3CNT_H
>> 7) & 3) {
2516 sourceIncrement
= (u32
)-4;
2519 sourceIncrement
= 0;
2522 switch((DM3CNT_H
>> 5) & 3) {
2526 destIncrement
= (u32
)-4;
2533 if(systemVerbose
& VERBOSE_DMA3
) {
2534 int count
= (DM3CNT_L
? DM3CNT_L
: 0x10000) << 1;
2535 if(DM3CNT_H
& 0x0400)
2537 log("DMA3: s=%08x d=%08x c=%04x count=%08x\n", dma3Source
, dma3Dest
,
2542 doDMA(dma3Source
, dma3Dest
, sourceIncrement
, destIncrement
,
2543 DM3CNT_L
? DM3CNT_L
: 0x10000,
2545 if(DM3CNT_H
& 0x4000) {
2547 UPDATE_REG(0x202, IF
);
2548 cpuNextEvent
= cpuTotalTicks
;
2551 if(((DM3CNT_H
>> 5) & 3) == 3) {
2552 dma3Dest
= DM3DAD_L
| (DM3DAD_H
<< 16);
2555 if(!(DM3CNT_H
& 0x0200) || (reason
== 0)) {
2557 UPDATE_REG(0xDE, DM3CNT_H
);
2563 void CPUUpdateRegister(u32 address
, u16 value
)
2569 DISPCNT
= (value
&7);
2570 bool change
= ((DISPCNT
^ value
) & 0x80) ? true : false;
2571 bool changeBG
= ((DISPCNT
^ value
) & 0x0F00) ? true : false;
2572 u16 changeBGon
= (((~DISPCNT
) & value
) & 0x0F00);
2573 DISPCNT
= (value
& 0xFFF7);
2574 UPDATE_REG(0x00, DISPCNT
);
2579 layerEnable
= layerSettings
& value
& (~changeBGon
);
2582 layerEnable
= layerSettings
& value
;
2583 // CPUUpdateTicks();
2585 windowOn
= (layerEnable
& 0x6000) ? true : false;
2586 if(change
&& !((value
& 0x80))) {
2587 if(!(DISPSTAT
& 1)) {
2590 // UPDATE_REG(0x06, VCOUNT);
2592 UPDATE_REG(0x04, DISPSTAT
);
2598 // we only care about changes in BG0-BG3
2600 CPUUpdateRenderBuffers(false);
2604 DISPSTAT
= (value
& 0xFF38) | (DISPSTAT
& 7);
2605 UPDATE_REG(0x04, DISPSTAT
);
2611 BG0CNT
= (value
& 0xDFCF);
2612 UPDATE_REG(0x08, BG0CNT
);
2615 BG1CNT
= (value
& 0xDFCF);
2616 UPDATE_REG(0x0A, BG1CNT
);
2619 BG2CNT
= (value
& 0xFFCF);
2620 UPDATE_REG(0x0C, BG2CNT
);
2623 BG3CNT
= (value
& 0xFFCF);
2624 UPDATE_REG(0x0E, BG3CNT
);
2627 BG0HOFS
= value
& 511;
2628 UPDATE_REG(0x10, BG0HOFS
);
2631 BG0VOFS
= value
& 511;
2632 UPDATE_REG(0x12, BG0VOFS
);
2635 BG1HOFS
= value
& 511;
2636 UPDATE_REG(0x14, BG1HOFS
);
2639 BG1VOFS
= value
& 511;
2640 UPDATE_REG(0x16, BG1VOFS
);
2643 BG2HOFS
= value
& 511;
2644 UPDATE_REG(0x18, BG2HOFS
);
2647 BG2VOFS
= value
& 511;
2648 UPDATE_REG(0x1A, BG2VOFS
);
2651 BG3HOFS
= value
& 511;
2652 UPDATE_REG(0x1C, BG3HOFS
);
2655 BG3VOFS
= value
& 511;
2656 UPDATE_REG(0x1E, BG3VOFS
);
2660 UPDATE_REG(0x20, BG2PA
);
2664 UPDATE_REG(0x22, BG2PB
);
2668 UPDATE_REG(0x24, BG2PC
);
2672 UPDATE_REG(0x26, BG2PD
);
2676 UPDATE_REG(0x28, BG2X_L
);
2680 BG2X_H
= (value
& 0xFFF);
2681 UPDATE_REG(0x2A, BG2X_H
);
2686 UPDATE_REG(0x2C, BG2Y_L
);
2690 BG2Y_H
= value
& 0xFFF;
2691 UPDATE_REG(0x2E, BG2Y_H
);
2696 UPDATE_REG(0x30, BG3PA
);
2700 UPDATE_REG(0x32, BG3PB
);
2704 UPDATE_REG(0x34, BG3PC
);
2708 UPDATE_REG(0x36, BG3PD
);
2712 UPDATE_REG(0x38, BG3X_L
);
2716 BG3X_H
= value
& 0xFFF;
2717 UPDATE_REG(0x3A, BG3X_H
);
2722 UPDATE_REG(0x3C, BG3Y_L
);
2726 BG3Y_H
= value
& 0xFFF;
2727 UPDATE_REG(0x3E, BG3Y_H
);
2732 UPDATE_REG(0x40, WIN0H
);
2737 UPDATE_REG(0x42, WIN1H
);
2742 UPDATE_REG(0x44, WIN0V
);
2746 UPDATE_REG(0x46, WIN1V
);
2749 WININ
= value
& 0x3F3F;
2750 UPDATE_REG(0x48, WININ
);
2753 WINOUT
= value
& 0x3F3F;
2754 UPDATE_REG(0x4A, WINOUT
);
2758 UPDATE_REG(0x4C, MOSAIC
);
2761 BLDMOD
= value
& 0x3FFF;
2762 UPDATE_REG(0x50, BLDMOD
);
2763 fxOn
= ((BLDMOD
>>6)&3) != 0;
2767 COLEV
= value
& 0x1F1F;
2768 UPDATE_REG(0x52, COLEV
);
2771 COLY
= value
& 0x1F;
2772 UPDATE_REG(0x54, COLY
);
2786 soundEvent(address
&0xFF, (u8
)(value
& 0xFF));
2787 soundEvent((address
&0xFF)+1, (u8
)(value
>>8));
2803 soundEvent(address
&0xFF, value
);
2807 UPDATE_REG(0xB0, DM0SAD_L
);
2810 DM0SAD_H
= value
& 0x07FF;
2811 UPDATE_REG(0xB2, DM0SAD_H
);
2815 UPDATE_REG(0xB4, DM0DAD_L
);
2818 DM0DAD_H
= value
& 0x07FF;
2819 UPDATE_REG(0xB6, DM0DAD_H
);
2822 DM0CNT_L
= value
& 0x3FFF;
2823 UPDATE_REG(0xB8, 0);
2827 bool start
= ((DM0CNT_H
^ value
) & 0x8000) ? true : false;
2831 UPDATE_REG(0xBA, DM0CNT_H
);
2833 if(start
&& (value
& 0x8000)) {
2834 dma0Source
= DM0SAD_L
| (DM0SAD_H
<< 16);
2835 dma0Dest
= DM0DAD_L
| (DM0DAD_H
<< 16);
2842 UPDATE_REG(0xBC, DM1SAD_L
);
2845 DM1SAD_H
= value
& 0x0FFF;
2846 UPDATE_REG(0xBE, DM1SAD_H
);
2850 UPDATE_REG(0xC0, DM1DAD_L
);
2853 DM1DAD_H
= value
& 0x07FF;
2854 UPDATE_REG(0xC2, DM1DAD_H
);
2857 DM1CNT_L
= value
& 0x3FFF;
2858 UPDATE_REG(0xC4, 0);
2862 bool start
= ((DM1CNT_H
^ value
) & 0x8000) ? true : false;
2866 UPDATE_REG(0xC6, DM1CNT_H
);
2868 if(start
&& (value
& 0x8000)) {
2869 dma1Source
= DM1SAD_L
| (DM1SAD_H
<< 16);
2870 dma1Dest
= DM1DAD_L
| (DM1DAD_H
<< 16);
2877 UPDATE_REG(0xC8, DM2SAD_L
);
2880 DM2SAD_H
= value
& 0x0FFF;
2881 UPDATE_REG(0xCA, DM2SAD_H
);
2885 UPDATE_REG(0xCC, DM2DAD_L
);
2888 DM2DAD_H
= value
& 0x07FF;
2889 UPDATE_REG(0xCE, DM2DAD_H
);
2892 DM2CNT_L
= value
& 0x3FFF;
2893 UPDATE_REG(0xD0, 0);
2897 bool start
= ((DM2CNT_H
^ value
) & 0x8000) ? true : false;
2902 UPDATE_REG(0xD2, DM2CNT_H
);
2904 if(start
&& (value
& 0x8000)) {
2905 dma2Source
= DM2SAD_L
| (DM2SAD_H
<< 16);
2906 dma2Dest
= DM2DAD_L
| (DM2DAD_H
<< 16);
2914 UPDATE_REG(0xD4, DM3SAD_L
);
2917 DM3SAD_H
= value
& 0x0FFF;
2918 UPDATE_REG(0xD6, DM3SAD_H
);
2922 UPDATE_REG(0xD8, DM3DAD_L
);
2925 DM3DAD_H
= value
& 0x0FFF;
2926 UPDATE_REG(0xDA, DM3DAD_H
);
2930 UPDATE_REG(0xDC, 0);
2934 bool start
= ((DM3CNT_H
^ value
) & 0x8000) ? true : false;
2939 UPDATE_REG(0xDE, DM3CNT_H
);
2941 if(start
&& (value
& 0x8000)) {
2942 dma3Source
= DM3SAD_L
| (DM3SAD_H
<< 16);
2943 dma3Dest
= DM3DAD_L
| (DM3DAD_H
<< 16);
2949 timer0Reload
= value
;
2952 timer0Value
= value
;
2954 cpuNextEvent
= cpuTotalTicks
;
2957 timer1Reload
= value
;
2960 timer1Value
= value
;
2962 cpuNextEvent
= cpuTotalTicks
;
2965 timer2Reload
= value
;
2968 timer2Value
= value
;
2970 cpuNextEvent
= cpuTotalTicks
;
2973 timer3Reload
= value
;
2976 timer3Value
= value
;
2978 cpuNextEvent
= cpuTotalTicks
;
2983 if(value
& 1 && (value
& 0x4000)) {
2984 UPDATE_REG(0x12a, 0xFF);
2986 UPDATE_REG(0x202, IF
);
2990 UPDATE_REG(0x128, value
);
2993 P1
|= (value
& 0x3FF);
2994 UPDATE_REG(0x130, P1
);
2997 UPDATE_REG(0x132, value
& 0xC3FF);
3000 IE
= value
& 0x3FFF;
3001 UPDATE_REG(0x200, IE
);
3002 if ((IME
& 1) && (IF
& IE
) && armIrqEnable
)
3003 cpuNextEvent
= cpuTotalTicks
;
3007 UPDATE_REG(0x202, IF
);
3011 memoryWait
[0x0e] = memoryWaitSeq
[0x0e] = gamepakRamWaitState
[value
& 3];
3014 memoryWait
[0x08] = memoryWait
[0x09] = gamepakWaitState
[(value
>> 2) & 3];
3015 memoryWaitSeq
[0x08] = memoryWaitSeq
[0x09] =
3016 gamepakWaitState0
[(value
>> 4) & 1];
3018 memoryWait
[0x0a] = memoryWait
[0x0b] = gamepakWaitState
[(value
>> 5) & 3];
3019 memoryWaitSeq
[0x0a] = memoryWaitSeq
[0x0b] =
3020 gamepakWaitState1
[(value
>> 7) & 1];
3022 memoryWait
[0x0c] = memoryWait
[0x0d] = gamepakWaitState
[(value
>> 8) & 3];
3023 memoryWaitSeq
[0x0c] = memoryWaitSeq
[0x0d] =
3024 gamepakWaitState2
[(value
>> 10) & 1];
3026 memoryWait
[0x08] = memoryWait
[0x09] = 3;
3027 memoryWaitSeq
[0x08] = memoryWaitSeq
[0x09] = 1;
3029 memoryWait
[0x0a] = memoryWait
[0x0b] = 3;
3030 memoryWaitSeq
[0x0a] = memoryWaitSeq
[0x0b] = 1;
3032 memoryWait
[0x0c] = memoryWait
[0x0d] = 3;
3033 memoryWaitSeq
[0x0c] = memoryWaitSeq
[0x0d] = 1;
3036 for(int i
= 8; i
< 15; i
++) {
3037 memoryWait32
[i
] = memoryWait
[i
] + memoryWaitSeq
[i
] + 1;
3038 memoryWaitSeq32
[i
] = memoryWaitSeq
[i
]*2 + 1;
3041 if((value
& 0x4000) == 0x4000) {
3042 busPrefetchEnable
= true;
3043 busPrefetch
= false;
3044 busPrefetchCount
= 0;
3046 busPrefetchEnable
= false;
3047 busPrefetch
= false;
3048 busPrefetchCount
= 0;
3050 UPDATE_REG(0x204, value
& 0x7FFF);
3056 UPDATE_REG(0x208, IME
);
3057 if ((IME
& 1) && (IF
& IE
) && armIrqEnable
)
3058 cpuNextEvent
= cpuTotalTicks
;
3063 UPDATE_REG(0x300, value
);
3066 UPDATE_REG(address
&0x3FE, value
);
3073 if (timerOnOffDelay
& 1)
3075 timer0ClockReload
= TIMER_TICKS
[timer0Value
& 3];
3076 if(!timer0On
&& (timer0Value
& 0x80)) {
3077 // reload the counter
3078 TM0D
= timer0Reload
;
3079 timer0Ticks
= (0x10000 - TM0D
) << timer0ClockReload
;
3080 UPDATE_REG(0x100, TM0D
);
3082 timer0On
= timer0Value
& 0x80 ? true : false;
3083 TM0CNT
= timer0Value
& 0xC7;
3084 UPDATE_REG(0x102, TM0CNT
);
3085 // CPUUpdateTicks();
3087 if (timerOnOffDelay
& 2)
3089 timer1ClockReload
= TIMER_TICKS
[timer1Value
& 3];
3090 if(!timer1On
&& (timer1Value
& 0x80)) {
3091 // reload the counter
3092 TM1D
= timer1Reload
;
3093 timer1Ticks
= (0x10000 - TM1D
) << timer1ClockReload
;
3094 UPDATE_REG(0x104, TM1D
);
3096 timer1On
= timer1Value
& 0x80 ? true : false;
3097 TM1CNT
= timer1Value
& 0xC7;
3098 UPDATE_REG(0x106, TM1CNT
);
3100 if (timerOnOffDelay
& 4)
3102 timer2ClockReload
= TIMER_TICKS
[timer2Value
& 3];
3103 if(!timer2On
&& (timer2Value
& 0x80)) {
3104 // reload the counter
3105 TM2D
= timer2Reload
;
3106 timer2Ticks
= (0x10000 - TM2D
) << timer2ClockReload
;
3107 UPDATE_REG(0x108, TM2D
);
3109 timer2On
= timer2Value
& 0x80 ? true : false;
3110 TM2CNT
= timer2Value
& 0xC7;
3111 UPDATE_REG(0x10A, TM2CNT
);
3113 if (timerOnOffDelay
& 8)
3115 timer3ClockReload
= TIMER_TICKS
[timer3Value
& 3];
3116 if(!timer3On
&& (timer3Value
& 0x80)) {
3117 // reload the counter
3118 TM3D
= timer3Reload
;
3119 timer3Ticks
= (0x10000 - TM3D
) << timer3ClockReload
;
3120 UPDATE_REG(0x10C, TM3D
);
3122 timer3On
= timer3Value
& 0x80 ? true : false;
3123 TM3CNT
= timer3Value
& 0xC7;
3124 UPDATE_REG(0x10E, TM3CNT
);
3126 cpuNextEvent
= CPUUpdateTicks();
3127 timerOnOffDelay
= 0;
3130 void CPUWriteHalfWord(u32 address
, u16 value
)
3134 if(systemVerbose
& VERBOSE_UNALIGNED_MEMORY
) {
3135 log("Unaligned halfword write: %04x to %08x from %08x\n",
3138 armMode
? armNextPC
- 4 : armNextPC
- 2);
3143 switch(address
>> 24) {
3146 if(*((u16
*)&freezeWorkRAM
[address
& 0x3FFFE]))
3147 cheatsWriteHalfWord(address
& 0x203FFFE,
3151 WRITE16LE(((u16
*)&workRAM
[address
& 0x3FFFE]),value
);
3155 if(*((u16
*)&freezeInternalRAM
[address
& 0x7ffe]))
3156 cheatsWriteHalfWord(address
& 0x3007ffe,
3160 WRITE16LE(((u16
*)&internalRAM
[address
& 0x7ffe]), value
);
3163 if(address
< 0x4000400)
3164 CPUUpdateRegister(address
& 0x3fe, value
);
3165 else goto unwritable
;
3169 if(*((u16
*)&freezePRAM
[address
& 0x03fe]))
3170 cheatsWriteHalfWord(address
& 0x70003fe,
3174 WRITE16LE(((u16
*)&paletteRAM
[address
& 0x3fe]), value
);
3177 address
= (address
& 0x1fffe);
3178 if (((DISPCNT
& 7) >2) && ((address
& 0x1C000) == 0x18000))
3180 if ((address
& 0x18000) == 0x18000)
3183 if(*((u16
*)&freezeVRAM
[address
]))
3184 cheatsWriteHalfWord(address
+ 0x06000000,
3188 WRITE16LE(((u16
*)&vram
[address
]), value
);
3192 if(*((u16
*)&freezeOAM
[address
& 0x03fe]))
3193 cheatsWriteHalfWord(address
& 0x70003fe,
3197 WRITE16LE(((u16
*)&oam
[address
& 0x3fe]), value
);
3201 if(address
== 0x80000c4 || address
== 0x80000c6 || address
== 0x80000c8) {
3202 if(!rtcWrite(address
, value
))
3204 } else if(!agbPrintWrite(address
, value
)) goto unwritable
;
3207 if(cpuEEPROMEnabled
) {
3208 eepromWrite(address
, (u8
)value
);
3213 if(!eepromInUse
| cpuSramEnabled
| cpuFlashEnabled
) {
3214 (*cpuSaveGameFunc
)(address
, (u8
)value
);
3221 if(systemVerbose
& VERBOSE_ILLEGAL_WRITE
) {
3222 log("Illegal halfword write: %04x to %08x from %08x\n",
3225 armMode
? armNextPC
- 4 : armNextPC
- 2);
3232 void CPUWriteByte(u32 address
, u8 b
)
3234 switch(address
>> 24) {
3237 if(freezeWorkRAM
[address
& 0x3FFFF])
3238 cheatsWriteByte(address
& 0x203FFFF, b
);
3241 workRAM
[address
& 0x3FFFF] = b
;
3245 if(freezeInternalRAM
[address
& 0x7fff])
3246 cheatsWriteByte(address
& 0x3007fff, b
);
3249 internalRAM
[address
& 0x7fff] = b
;
3252 if(address
< 0x4000400) {
3253 switch(address
& 0x3FF) {
3259 cpuNextEvent
= cpuTotalTicks
;
3301 soundEvent(address
&0xFF, b
);
3305 CPUUpdateRegister(address
& 0x3fe,
3306 ((READ16LE(((u16
*)&ioMem
[address
& 0x3fe])))
3310 CPUUpdateRegister(address
& 0x3fe,
3311 ((READ16LE(((u16
*)&ioMem
[address
& 0x3fe])) & 0xFF00) | b
));
3314 } else goto unwritable
;
3317 // no need to switch
3318 *((u16
*)&paletteRAM
[address
& 0x3FE]) = (b
<< 8) | b
;
3321 address
= (address
& 0x1fffe);
3322 if (((DISPCNT
& 7) >2) && ((address
& 0x1C000) == 0x18000))
3324 if ((address
& 0x18000) == 0x18000)
3327 // no need to switch
3328 // byte writes to OBJ VRAM are ignored
3329 if ((address
) < objTilesAddress
[((DISPCNT
&7)+1)>>2])
3332 if(freezeVRAM
[address
])
3333 cheatsWriteByte(address
+ 0x06000000, b
);
3336 *((u16
*)&vram
[address
]) = (b
<< 8) | b
;
3340 // no need to switch
3341 // byte writes to OAM are ignored
3342 // *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b;
3345 if(cpuEEPROMEnabled
) {
3346 eepromWrite(address
, b
);
3351 if (!(saveType
== 5) && (!eepromInUse
| cpuSramEnabled
| cpuFlashEnabled
)) {
3353 //if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) {
3355 (*cpuSaveGameFunc
)(address
, b
);
3362 if(systemVerbose
& VERBOSE_ILLEGAL_WRITE
) {
3363 log("Illegal byte write: %02x to %08x from %08x\n",
3366 armMode
? armNextPC
- 4 : armNextPC
-2 );
3374 u8 cpuLowestBitSet
[256];
3376 void CPUInit(const char *biosFileName
, bool useBiosFile
)
3378 #ifdef WORDS_BIGENDIAN
3379 if(!cpuBiosSwapped
) {
3380 for(unsigned int i
= 0; i
< sizeof(myROM
)/4; i
++) {
3381 WRITE32LE(&myROM
[i
], myROM
[i
]);
3383 cpuBiosSwapped
= true;
3393 if(utilLoad(biosFileName
,
3400 systemMessage(MSG_INVALID_BIOS_FILE_SIZE
, N_("Invalid BIOS file size"));
3405 memcpy(bios
, myROM
, sizeof(myROM
));
3410 biosProtected
[0] = 0x00;
3411 biosProtected
[1] = 0xf0;
3412 biosProtected
[2] = 0x29;
3413 biosProtected
[3] = 0xe1;
3415 for(i
= 0; i
< 256; i
++) {
3418 for(j
= 0; j
< 8; j
++)
3421 cpuBitsSet
[i
] = count
;
3423 for(j
= 0; j
< 8; j
++)
3426 cpuLowestBitSet
[i
] = j
;
3429 for(i
= 0; i
< 0x400; i
++)
3430 ioReadable
[i
] = true;
3431 for(i
= 0x10; i
< 0x48; i
++)
3432 ioReadable
[i
] = false;
3433 for(i
= 0x4c; i
< 0x50; i
++)
3434 ioReadable
[i
] = false;
3435 for(i
= 0x54; i
< 0x60; i
++)
3436 ioReadable
[i
] = false;
3437 for(i
= 0x8c; i
< 0x90; i
++)
3438 ioReadable
[i
] = false;
3439 for(i
= 0xa0; i
< 0xb8; i
++)
3440 ioReadable
[i
] = false;
3441 for(i
= 0xbc; i
< 0xc4; i
++)
3442 ioReadable
[i
] = false;
3443 for(i
= 0xc8; i
< 0xd0; i
++)
3444 ioReadable
[i
] = false;
3445 for(i
= 0xd4; i
< 0xdc; i
++)
3446 ioReadable
[i
] = false;
3447 for(i
= 0xe0; i
< 0x100; i
++)
3448 ioReadable
[i
] = false;
3449 for(i
= 0x110; i
< 0x120; i
++)
3450 ioReadable
[i
] = false;
3451 for(i
= 0x12c; i
< 0x130; i
++)
3452 ioReadable
[i
] = false;
3453 for(i
= 0x138; i
< 0x140; i
++)
3454 ioReadable
[i
] = false;
3455 for(i
= 0x144; i
< 0x150; i
++)
3456 ioReadable
[i
] = false;
3457 for(i
= 0x15c; i
< 0x200; i
++)
3458 ioReadable
[i
] = false;
3459 for(i
= 0x20c; i
< 0x300; i
++)
3460 ioReadable
[i
] = false;
3461 for(i
= 0x304; i
< 0x400; i
++)
3462 ioReadable
[i
] = false;
3464 if(romSize
< 0x1fe2000) {
3465 *((u16
*)&rom
[0x1fe209c]) = 0xdffa; // SWI 0xFA
3466 *((u16
*)&rom
[0x1fe209e]) = 0x4770; // BX LR
3468 agbPrintEnable(false);
3474 if(gbaSaveType
== 0) {
3489 memset(®
[0], 0, sizeof(reg
));
3491 memset(oam
, 0, 0x400);
3493 memset(paletteRAM
, 0, 0x400);
3495 memset(pix
, 0, 4*160*240);
3497 memset(vram
, 0, 0x20000);
3499 memset(ioMem
, 0, 0x400);
3503 VCOUNT
= (useBios
&& !skipBios
) ? 0 :0x007E;
3581 if(cpuIsMultiBoot
) {
3582 reg
[13].I
= 0x03007F00;
3583 reg
[15].I
= 0x02000000;
3584 reg
[16].I
= 0x00000000;
3585 reg
[R13_IRQ
].I
= 0x03007FA0;
3586 reg
[R13_SVC
].I
= 0x03007FE0;
3587 armIrqEnable
= true;
3589 if(useBios
&& !skipBios
) {
3590 reg
[15].I
= 0x00000000;
3592 armIrqEnable
= false;
3594 reg
[13].I
= 0x03007F00;
3595 reg
[15].I
= 0x08000000;
3596 reg
[16].I
= 0x00000000;
3597 reg
[R13_IRQ
].I
= 0x03007FA0;
3598 reg
[R13_SVC
].I
= 0x03007FE0;
3599 armIrqEnable
= true;
3603 C_FLAG
= V_FLAG
= N_FLAG
= Z_FLAG
= false;
3604 UPDATE_REG(0x00, DISPCNT
);
3605 UPDATE_REG(0x06, VCOUNT
);
3606 UPDATE_REG(0x20, BG2PA
);
3607 UPDATE_REG(0x26, BG2PD
);
3608 UPDATE_REG(0x30, BG3PA
);
3609 UPDATE_REG(0x36, BG3PD
);
3610 UPDATE_REG(0x130, P1
);
3611 UPDATE_REG(0x88, 0x200);
3618 armNextPC
= reg
[15].I
;
3621 // reset internal state
3625 biosProtected
[0] = 0x00;
3626 biosProtected
[1] = 0xf0;
3627 biosProtected
[2] = 0x29;
3628 biosProtected
[3] = 0xe1;
3630 lcdTicks
= (useBios
&& !skipBios
) ? 1008 : 208;
3634 timer0ClockReload
= 0;
3638 timer1ClockReload
= 0;
3642 timer2ClockReload
= 0;
3646 timer3ClockReload
= 0;
3655 cpuSaveGameFunc
= flashSaveDecide
;
3656 renderLine
= mode0RenderLine
;
3661 layerEnable
= DISPCNT
& layerSettings
;
3663 CPUUpdateRenderBuffers(true);
3665 for(int i
= 0; i
< 256; i
++) {
3666 map
[i
].address
= (u8
*)&dummyAddress
;
3670 map
[0].address
= bios
;
3671 map
[0].mask
= 0x3FFF;
3672 map
[2].address
= workRAM
;
3673 map
[2].mask
= 0x3FFFF;
3674 map
[3].address
= internalRAM
;
3675 map
[3].mask
= 0x7FFF;
3676 map
[4].address
= ioMem
;
3677 map
[4].mask
= 0x3FF;
3678 map
[5].address
= paletteRAM
;
3679 map
[5].mask
= 0x3FF;
3680 map
[6].address
= vram
;
3681 map
[6].mask
= 0x1FFFF;
3682 map
[7].address
= oam
;
3683 map
[7].mask
= 0x3FF;
3684 map
[8].address
= rom
;
3685 map
[8].mask
= 0x1FFFFFF;
3686 map
[9].address
= rom
;
3687 map
[9].mask
= 0x1FFFFFF;
3688 map
[10].address
= rom
;
3689 map
[10].mask
= 0x1FFFFFF;
3690 map
[12].address
= rom
;
3691 map
[12].mask
= 0x1FFFFFF;
3692 map
[14].address
= flashSaveMemory
;
3693 map
[14].mask
= 0xFFFF;
3703 // make sure registers are correctly initialized if not using BIOS
3706 BIOS_RegisterRamReset(0xfe);
3708 BIOS_RegisterRamReset(0xff);
3711 BIOS_RegisterRamReset(0xfe);
3714 switch(cpuSaveType
) {
3715 case 0: // automatic
3716 cpuSramEnabled
= true;
3717 cpuFlashEnabled
= true;
3718 cpuEEPROMEnabled
= true;
3719 cpuEEPROMSensorEnabled
= false;
3720 saveType
= gbaSaveType
= 0;
3723 cpuSramEnabled
= false;
3724 cpuFlashEnabled
= false;
3725 cpuEEPROMEnabled
= true;
3726 cpuEEPROMSensorEnabled
= false;
3727 saveType
= gbaSaveType
= 3;
3728 // EEPROM usage is automatically detected
3731 cpuSramEnabled
= true;
3732 cpuFlashEnabled
= false;
3733 cpuEEPROMEnabled
= false;
3734 cpuEEPROMSensorEnabled
= false;
3735 cpuSaveGameFunc
= sramDelayedWrite
; // to insure we detect the write
3736 saveType
= gbaSaveType
= 1;
3739 cpuSramEnabled
= false;
3740 cpuFlashEnabled
= true;
3741 cpuEEPROMEnabled
= false;
3742 cpuEEPROMSensorEnabled
= false;
3743 cpuSaveGameFunc
= flashDelayedWrite
; // to insure we detect the write
3744 saveType
= gbaSaveType
= 2;
3746 case 4: // EEPROM+Sensor
3747 cpuSramEnabled
= false;
3748 cpuFlashEnabled
= false;
3749 cpuEEPROMEnabled
= true;
3750 cpuEEPROMSensorEnabled
= true;
3751 // EEPROM usage is automatically detected
3752 saveType
= gbaSaveType
= 3;
3755 cpuSramEnabled
= false;
3756 cpuFlashEnabled
= false;
3757 cpuEEPROMEnabled
= false;
3758 cpuEEPROMSensorEnabled
= false;
3760 saveType
= gbaSaveType
= 5;
3766 systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
3770 lastTime
= systemGetClock();
3778 bool savedState
= armState
;
3779 CPUSwitchMode(0x12, true, false);
3785 armIrqEnable
= false;
3787 armNextPC
= reg
[15].I
;
3792 biosProtected
[0] = 0x02;
3793 biosProtected
[1] = 0xc0;
3794 biosProtected
[2] = 0x5e;
3795 biosProtected
[3] = 0xe5;
3799 void log(const char *defaultMsg
, ...)
3804 va_start(valist
, defaultMsg
);
3805 vsprintf(buffer
, defaultMsg
, valist
);
3808 out
= fopen("trace.log","w");
3816 extern void winlog(const char *, ...);
3819 void CPULoop(int ticks
)
3822 int timerOverflow
= 0;
3823 // variable used by the CPU core
3825 cpuBreakLoop
= false;
3826 cpuNextEvent
= CPUUpdateTicks();
3827 if(cpuNextEvent
> ticks
)
3828 cpuNextEvent
= ticks
;
3832 #ifndef FINAL_VERSION
3834 if(systemDebug
>= 10 && !holdState
) {
3839 sprintf(buffer
, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n",
3840 oldreg
[0], oldreg
[1], oldreg
[2], oldreg
[3], oldreg
[4], oldreg
[5],
3841 oldreg
[6], oldreg
[7], oldreg
[8], oldreg
[9], oldreg
[10], oldreg
[11],
3842 oldreg
[12], oldreg
[13], oldreg
[14], oldreg
[15], oldreg
[16],
3846 sprintf(buffer
, "R00=%08x R01=%08x R02=%08x R03=%08x R04=%08x R05=%08x R06=%08x R07=%08x R08=%08x R09=%08x R10=%08x R11=%08x R12=%08x R13=%08x R14=%08x R15=%08x R16=%08x R17=%08x\n",
3847 reg
[0].I
, reg
[1].I
, reg
[2].I
, reg
[3].I
, reg
[4].I
, reg
[5].I
,
3848 reg
[6].I
, reg
[7].I
, reg
[8].I
, reg
[9].I
, reg
[10].I
, reg
[11].I
,
3849 reg
[12].I
, reg
[13].I
, reg
[14].I
, reg
[15].I
, reg
[16].I
,
3856 } else if(!holdState
) {
3857 sprintf(buffer
, "PC=%08x\n", armNextPC
);
3865 #endif /* FINAL_VERSION */
3867 if(!holdState
&& !SWITicks
) {
3869 // Emulates the Cheat System (m) code
3870 if((cheatsEnabled
) && (mastercode
) && (mastercode
== armNextPC
))
3873 if(systemReadJoypads())
3874 joy
= systemReadJoypad(-1);
3875 u32 ext
= (joy
>> 10);
3876 cpuTotalTicks
+= cheatsCheckKeys(P1
^0x3FF, ext
);
3879 if ((armNextPC
& 0x0803FFFF) == 0x08020000)
3880 busPrefetchCount
=0x100;
3883 #include "arm-new.h"
3888 clockTicks
= CPUUpdateTicks();
3890 cpuTotalTicks
+= clockTicks
;
3893 if(cpuTotalTicks
>= cpuNextEvent
) {
3894 int remainingTicks
= cpuTotalTicks
- cpuNextEvent
;
3898 SWITicks
-=clockTicks
;
3903 clockTicks
= cpuNextEvent
;
3911 IRQTicks
-= clockTicks
;
3916 lcdTicks
-= clockTicks
;
3920 if(DISPSTAT
& 1) { // V-BLANK
3921 // if in V-Blank mode, keep computing...
3925 UPDATE_REG(0x06, VCOUNT
);
3927 UPDATE_REG(0x04, DISPSTAT
);
3932 UPDATE_REG(0x04, DISPSTAT
);
3935 UPDATE_REG(0x202, IF
);
3939 if(VCOUNT
>= 228) { //Reaching last line
3941 UPDATE_REG(0x04, DISPSTAT
);
3943 UPDATE_REG(0x06, VCOUNT
);
3947 int framesToSkip
= systemFrameSkip
;
3949 framesToSkip
= 9; // try 6 FPS during speedup
3952 // if in H-Blank, leave it and move to drawing mode
3954 UPDATE_REG(0x06, VCOUNT
);
3962 if((count
% 10) == 0) {
3966 u32 time
= systemGetClock();
3967 if(time
!= lastTime
) {
3968 u32 t
= 100000/(time
- lastTime
);
3976 // update joystick information
3977 if(systemReadJoypads())
3978 // read default joystick
3979 joy
= systemReadJoypad(-1);
3980 P1
= 0x03FF ^ (joy
& 0x3FF);
3981 if(cpuEEPROMSensorEnabled
)
3982 systemUpdateMotionSensor();
3983 UPDATE_REG(0x130, P1
);
3984 u16 P1CNT
= READ16LE(((u16
*)&ioMem
[0x132]));
3985 // this seems wrong, but there are cases where the game
3986 // can enter the stop state without requesting an IRQ from
3988 if((P1CNT
& 0x4000) || stopState
) {
3989 u16 p1
= (0x3FF ^ P1
) & 0x3FF;
3990 if(P1CNT
& 0x8000) {
3991 if(p1
== (P1CNT
& 0x3FF)) {
3993 UPDATE_REG(0x202, IF
);
3998 UPDATE_REG(0x202, IF
);
4003 u32 ext
= (joy
>> 10);
4004 // If no (m) code is enabled, apply the cheats at each LCDline
4005 if((cheatsEnabled
) && (mastercode
==0))
4006 remainingTicks
+= cheatsCheckKeys(P1
^0x3FF, ext
);
4007 speedup
= (ext
& 1) ? true : false;
4008 capture
= (ext
& 2) ? true : false;
4010 if(capture
&& !capturePrevious
) {
4012 systemScreenCapture(captureNumber
);
4014 capturePrevious
= capture
;
4018 UPDATE_REG(0x04, DISPSTAT
);
4019 if(DISPSTAT
& 0x0008) {
4021 UPDATE_REG(0x202, IF
);
4023 CPUCheckDMA(1, 0x0f);
4024 if(frameCount
>= framesToSkip
) {
4029 if(systemPauseOnFrame())
4033 UPDATE_REG(0x04, DISPSTAT
);
4037 if(frameCount
>= framesToSkip
)
4040 switch(systemColorDepth
) {
4043 u16
*dest
= (u16
*)pix
+ 242 * (VCOUNT
+1);
4044 for(int x
= 0; x
< 240;) {
4045 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4046 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4047 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4048 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4050 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4051 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4052 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4053 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4055 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4056 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4057 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4058 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4060 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4061 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4062 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4063 *dest
++ = systemColorMap16
[lineMix
[x
++]&0xFFFF];
4065 // for filters that read past the screen
4071 u8
*dest
= (u8
*)pix
+ 240 * VCOUNT
* 3;
4072 for(int x
= 0; x
< 240;) {
4073 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4075 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4077 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4079 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4082 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4084 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4086 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4088 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4091 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4093 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4095 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4097 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4100 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4102 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4104 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4106 *((u32
*)dest
) = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4113 u32
*dest
= (u32
*)pix
+ 241 * (VCOUNT
+1);
4114 for(int x
= 0; x
< 240; ) {
4115 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4116 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4117 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4118 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4120 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4121 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4122 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4123 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4125 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4126 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4127 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4128 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4130 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4131 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4132 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4133 *dest
++ = systemColorMap32
[lineMix
[x
++] & 0xFFFF];
4141 UPDATE_REG(0x04, DISPSTAT
);
4143 CPUCheckDMA(2, 0x0f);
4146 UPDATE_REG(0x202, IF
);
4154 timer0Ticks
-= clockTicks
;
4155 if(timer0Ticks
<= 0) {
4156 timer0Ticks
+= (0x10000 - timer0Reload
) << timer0ClockReload
;
4158 soundTimerOverflow(0);
4161 UPDATE_REG(0x202, IF
);
4164 TM0D
= 0xFFFF - (timer0Ticks
>> timer0ClockReload
);
4165 UPDATE_REG(0x100, TM0D
);
4170 if(timerOverflow
& 1) {
4173 TM1D
+= timer1Reload
;
4175 soundTimerOverflow(1);
4178 UPDATE_REG(0x202, IF
);
4181 UPDATE_REG(0x104, TM1D
);
4184 timer1Ticks
-= clockTicks
;
4185 if(timer1Ticks
<= 0) {
4186 timer1Ticks
+= (0x10000 - timer1Reload
) << timer1ClockReload
;
4188 soundTimerOverflow(1);
4191 UPDATE_REG(0x202, IF
);
4194 TM1D
= 0xFFFF - (timer1Ticks
>> timer1ClockReload
);
4195 UPDATE_REG(0x104, TM1D
);
4201 if(timerOverflow
& 2) {
4204 TM2D
+= timer2Reload
;
4208 UPDATE_REG(0x202, IF
);
4211 UPDATE_REG(0x108, TM2D
);
4214 timer2Ticks
-= clockTicks
;
4215 if(timer2Ticks
<= 0) {
4216 timer2Ticks
+= (0x10000 - timer2Reload
) << timer2ClockReload
;
4220 UPDATE_REG(0x202, IF
);
4223 TM2D
= 0xFFFF - (timer2Ticks
>> timer2ClockReload
);
4224 UPDATE_REG(0x108, TM2D
);
4230 if(timerOverflow
& 4) {
4233 TM3D
+= timer3Reload
;
4236 UPDATE_REG(0x202, IF
);
4239 UPDATE_REG(0x10C, TM3D
);
4242 timer3Ticks
-= clockTicks
;
4243 if(timer3Ticks
<= 0) {
4244 timer3Ticks
+= (0x10000 - timer3Reload
) << timer3ClockReload
;
4247 UPDATE_REG(0x202, IF
);
4250 TM3D
= 0xFFFF - (timer3Ticks
>> timer3ClockReload
);
4251 UPDATE_REG(0x10C, TM3D
);
4258 // we shouldn't be doing sound in stop state, but we loose synchronization
4259 // if sound is disabled, so in stop state, soundTick will just produce
4261 soundTicks
-= clockTicks
;
4262 if(soundTicks
<= 0) {
4264 soundTicks
+= SOUND_CLOCK_TICKS
;
4268 profilingTicks
-= clockTicks
;
4269 if(profilingTicks
<= 0) {
4270 profilingTicks
+= profilingTicksReload
;
4272 profile_segment
*seg
= profilSegment
;
4274 u16
*b
= (u16
*)seg
->sbuf
;
4275 int pc
= ((reg
[15].I
- seg
->s_lowpc
) * seg
->s_scale
)/0x10000;
4276 if(pc
>= 0 && pc
< seg
->ssiz
) {
4287 ticks
-= clockTicks
;
4289 cpuNextEvent
= CPUUpdateTicks();
4291 if(cpuDmaTicksToUpdate
> 0) {
4292 if(cpuDmaTicksToUpdate
> cpuNextEvent
)
4293 clockTicks
= cpuNextEvent
;
4295 clockTicks
= cpuDmaTicksToUpdate
;
4296 cpuDmaTicksToUpdate
-= clockTicks
;
4297 if(cpuDmaTicksToUpdate
< 0)
4298 cpuDmaTicksToUpdate
= 0;
4303 if(IF
&& (IME
& 1) && armIrqEnable
) {
4325 if (cpuNextEvent
> IRQTicks
)
4326 cpuNextEvent
= IRQTicks
;
4337 // Stops the SWI Ticks emulation if an IRQ is executed
4338 //(to avoid problems with nested IRQ/SWI)
4344 if(remainingTicks
> 0) {
4345 if(remainingTicks
> cpuNextEvent
)
4346 clockTicks
= cpuNextEvent
;
4348 clockTicks
= remainingTicks
;
4349 remainingTicks
-= clockTicks
;
4350 if(remainingTicks
< 0)
4355 if (timerOnOffDelay
)
4358 if(cpuNextEvent
> ticks
)
4359 cpuNextEvent
= ticks
;
4361 if(ticks
<= 0 || cpuBreakLoop
)
4370 struct EmulatedSystem GBASystem
= {
4380 CPUWriteBatteryFile
,
4398 #ifdef FINAL_VERSION