-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmmu.c
165 lines (132 loc) · 6.12 KB
/
mmu.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
----------------------------------------
MMU emulation (Memory Management Unit)
This file is part of the zBoy project.
Copyright (C) Mateusz Viste 2010, 2011
----------------------------------------
*/
enum mbc1_models {
MBC1_16_8 = 1,
MBC1_4_32 = 2
};
uint8_t _MemoryInternalRAM[0x2000]; /* Internal RAM Area [8KiB] */
uint8_t _MemoryInternalHiRAM[128]; /* Internal RAM (high area + IE register) */
uint8_t _MemoryBankedRAM[0x2000]; // 0x20A001]; /* Banked RAM [2MiB] */
uint8_t * const MemoryBankedRAM = _MemoryBankedRAM - 0xA000;
#ifdef EMBEDROM
const uint8_t MemoryROM[128*1024] = {
#include EMBEDROM
};
#else
const uint8_t MemoryROM[128*1024] = {0xDE, 0xAD, 0xBE, 0xEF, 0x1, 0};
#endif
uint8_t _VideoRAM[0x2000]; /* Video RAM [8KiB] */
uint8_t _SpriteOAM[0xA0]; /* Sprite OAM memory */
uint8_t _IoRegisters[0x80]; /* All I/O memory-mapped registers */
uint8_t * const MemoryInternalRAM = _MemoryInternalRAM - 0xC000; /* Internal RAM Area [8KiB] */
uint8_t * const MemoryInternalHiRAM = _MemoryInternalHiRAM - 0xFF80;
uint8_t * const VideoRAM = _VideoRAM - 0x8000; /* Video RAM [8KiB] */
uint8_t * const SpriteOAM = _SpriteOAM - 0xFE00; /* Sprite OAM memory */
uint8_t * const IoRegisters = _IoRegisters - 0xFF00; /* All I/O memory-mapped registers */
// uint8_t MemoryMAP[0x10000]; /* Regular memory (fallback for unmapped regions) */
int Mbc1Model = MBC1_16_8; /* MBC1 memory model (MbcModel can be 1 or 2) 1=16/8 ; 2=4/32 */
int CurRomBank = 0; /* Used for ROM bank switching (must be at least 9 bits long for MBC5 support!) */
int CurRamBank = 0; /* Current RAM bank selection */
// int SaveScoresWriteProtection[2048];
// uint8_t (*MemoryReadSpecial)(register int memaddr);
// void (*MemoryWriteSpecial)(register int memaddr, uint8_t DataByte);
// #define MemoryWriteSpecial MBC0_MemoryWrite
// #define MemoryReadSpecial MBC0_MemoryRead
void InitRAM(void) { /* Init the RAM areas to random values, as in a real GameBoy */
/*
FOR x = LBOUND(MemoryInternalRAM) TO UBOUND(MemoryInternalRAM)
MemoryInternalRAM(x) = INT(RND * 256)
NEXT x
FOR x = LBOUND(MemoryInternalHiRAM) TO UBOUND(MemoryInternalHiRAM)
MemoryInternalHiRAM(x) = INT(RND * 256)
NEXT x
FOR x = LBOUND(MemoryBankedRAM) TO UBOUND(MemoryBankedRAM)
MemoryBankedRAM(x) = INT(RND * 256)
NEXT x */
// for (int x = 0; x < 65536; x++) MemoryMAP[x] = (((unsigned) rand()) % 256);
}
/* Below are generic MemoryRead and MemoryWrite routines. These routines *
* check if the called address is a well-known address. If this address *
* is behaving the same on all known MBC controllers, then it is answered *
* here (and it is FAST). Otherwise, a Memory routine specialized for the *
* given MBC is called. */
uint8_t * const ramidx = (uint8_t *) 0x20000000;
uint8_t * RAMette[9] = {
MemoryROM,
_VideoRAM - 0x8000,
_MemoryInternalRAM - 0xC000,
_MemoryInternalRAM - 0xC000 - 8192,
_SpriteOAM - 0xFE00,
_IoRegisters - 0xFF00,
_MemoryInternalHiRAM - 0xFF80,
_MemoryBankedRAM - 0xA000,
MemoryROM
};
typedef void (*WriteHandlerT)( uint32_t, uint8_t d, uint8_t * );
extern const WriteHandlerT writeHandlers[];
void NULLWrite( uint32_t addr, uint8_t data, uint8_t *bank ){}
inline uint8_t *getMemoryBlock( int ReadAddr ){
return RAMette[ ramidx[ReadAddr>>5] ];
}
inline uint8_t MemoryRead(int ReadAddr) {
return RAMette[ ramidx[ReadAddr>>5] ][ ReadAddr ];
}
inline void MemoryWrite(uint32_t WriteAddr, uint8_t DataHolder) {
int id = ramidx[WriteAddr>>5];
writeHandlers[ id ]( WriteAddr, DataHolder, RAMette[id] );
}
void RAMWrite( uint32_t WriteAddr, uint8_t DataHolder, uint8_t *buffer ){
buffer[ WriteAddr ] = DataHolder;
}
uint8_t JoyRegA = 0, JoyRegB = 0, JoyOldReg;
// uint8_t *PCBuffer;
uint8_t MemoryRead( int );
inline void IOWrite(uint32_t WriteAddr, uint8_t DataHolder, uint8_t *IoRegisters){
if (WriteAddr == 0xFF41) { /* STAT register: Do not allow to write into 2 last bits of the STAT */
IoRegisters[0xFF41] = ((IoRegisters[0xFF41] & bx00000011) | (DataHolder & bx11111100)); /* register, as these bits are the mode flag. */
} else if (WriteAddr == 0xFF44) { /* CURLINE [RW] Current Scanline. */
IoRegisters[WriteAddr] = 0; /* Writing into this register resets it. */
/* SetUserMsg("LY RESET"); */
} else if (WriteAddr == 0xFF46) { /* Starts LCD OAM DMA transfer */
int x;
for( x = 0; x < 160; x++) { /* Let's copy XX00-XX9F to FE00-FE9F */
SpriteOAM[0xFE00 | x] = MemoryRead((DataHolder << 8) | x);
}
} else if (WriteAddr == 0xFF04) {
IoRegisters[0xFF04] = 0; /* Divide register: Writing any value sets it to 0 */
} else if (WriteAddr == 0xFF00) {
JoypadWrite( DataHolder );
} else { // if ((WriteAddr >= 0xFF00) && (WriteAddr <= 0xFF4B)) { /* I/O registers */
IoRegisters[WriteAddr] = DataHolder;
//} else if (WriteAddr <= 65535) {
// MemoryWriteSpecial(WriteAddr, DataHolder);
}
}
void JoypadWrite(uint8_t JoyNewReg){
if( (JoyNewReg & bx00100000) != 0) {
JoyNewReg &= 0xF0;
/* P14 selected (bit 4 is low) -> down/up/left/right */
JoyNewReg |= JoyRegA;
} else if ( (JoyNewReg & bx00010000) != 0) {
JoyNewReg &= 0xF0;
/* P15 selected (bit 5 is low) -> Start/Select/B/A */
JoyNewReg |= JoyRegB;
} else if ( JoyNewReg == 3){
/* no bits 4 & 5 set, maybe the game wants to get the system type... */
JoyNewReg = 0xF0; /* returns FXh to indicate a classic GameBoy device */
}
IoRegisters[0xFF00] = JoyNewReg; /* update the joypad register [FF00h] */
}
#ifdef MBC0
#include "mbc0.c" /* Support for ROM-ONLY ROMs */
#elif defined(MBC1)
#include "mbc1.c" /* Support for MBC1 memory controllers */
#endif
//#include "mbc2.c" /* Support for MBC2 memory controllers */
//#include "mbc3.c" /* Support for MBC3 memory controllers (without TIMER support so far) */
//#include "mbc5.c" /* Support for MBC5 memory controllers (usually found in GBC games) */