SayoriOS  0.3.3
mem.c
1 #include "lib/string.h"
2 #include "mem.h"
3 #include "rom.h"
4 #include "lcd.h"
5 #include "mbc.h"
6 #include "interrupt.h"
7 #include "timer.h"
8 #include "sdl.h"
9 #include "cpu.h"
10 
11 static unsigned const char bootrom[256] =
12 {
13  0x31, 0xFE, 0xFF, 0xAF, 0x21, 0xFF, 0x9F, 0x32, 0xCB, 0x7C, 0x20, 0xFB, 0x21, 0x26, 0xFF, 0x0E,
14  0x11, 0x3E, 0x80, 0x32, 0xE2, 0x0C, 0x3E, 0xF3, 0xE2, 0x32, 0x3E, 0x77, 0x77, 0x3E, 0xFC, 0xE0,
15  0x47, 0x11, 0x04, 0x01, 0x21, 0x10, 0x80, 0x1A, 0xCD, 0x95, 0x00, 0xCD, 0x96, 0x00, 0x13, 0x7B,
16  0xFE, 0x34, 0x20, 0xF3, 0x11, 0xD8, 0x00, 0x06, 0x08, 0x1A, 0x13, 0x22, 0x23, 0x05, 0x20, 0xF9,
17  0x3E, 0x19, 0xEA, 0x10, 0x99, 0x21, 0x2F, 0x99, 0x0E, 0x0C, 0x3D, 0x28, 0x08, 0x32, 0x0D, 0x20,
18  0xF9, 0x2E, 0x0F, 0x18, 0xF3, 0x67, 0x3E, 0x64, 0x57, 0xE0, 0x42, 0x3E, 0x91, 0xE0, 0x40, 0x04,
19  0x1E, 0x02, 0x0E, 0x0C, 0xF0, 0x44, 0xFE, 0x90, 0x20, 0xFA, 0x0D, 0x20, 0xF7, 0x1D, 0x20, 0xF2,
20  0x0E, 0x13, 0x24, 0x7C, 0x1E, 0x83, 0xFE, 0x62, 0x28, 0x06, 0x1E, 0xC1, 0xFE, 0x64, 0x20, 0x06,
21  0x7B, 0xE2, 0x0C, 0x3E, 0x87, 0xE2, 0xF0, 0x42, 0x90, 0xE0, 0x42, 0x15, 0x20, 0xD2, 0x05, 0x20,
22  0x4F, 0x16, 0x20, 0x18, 0xCB, 0x4F, 0x06, 0x04, 0xC5, 0xCB, 0x11, 0x17, 0xC1, 0xCB, 0x11, 0x17,
23  0x05, 0x20, 0xF5, 0x22, 0x23, 0x22, 0x23, 0xC9, 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B,
24  0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E,
25  0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC,
26  0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E, 0x3C, 0x42, 0xB9, 0xA5, 0xB9, 0xA5, 0x42, 0x3C,
27  0x21, 0x04, 0x01, 0x11, 0xA8, 0x00, 0x1A, 0x13, 0xBE, 0x20, 0xFE, 0x23, 0x7D, 0xFE, 0x34, 0x20,
28  0xF5, 0x06, 0x19, 0x78, 0x86, 0x23, 0x05, 0x20, 0xFB, 0x86, 0x20, 0xFE, 0x3E, 0x01, 0xE0, 0x50
29 };
30 
31 #ifdef DEBUG
32 static int bootrom_enabled = 0;
33 #else
34 static int bootrom_enabled = 1;
35 #endif
36 
37 static unsigned char *mem;
38 
39 static unsigned int DMA_pending;
40 static unsigned short DMA_src;
41 static int DMA_copied;
42 
43 static int joypad_select_buttons, joypad_select_directions;
44 
45 void mem_bank_switch(unsigned int n)
46 {
47  unsigned char *b = rom_getbytes();
48 
49  if(!rom_bank_valid(n))
50  {
51  printf("Bank switch to illegal bank %d, ignoring.\n", n);
52  return;
53  }
54 
55  memcpy(&mem[0x4000], &b[n * 0x4000], 0x4000);
56 }
57 
58 /* LCD's access to VRAM */
59 unsigned char mem_get_raw(unsigned short p)
60 {
61  return mem[p];
62 }
63 
64 unsigned char mem_get_byte(unsigned short i)
65 {
66  unsigned char mask = 0;
67 
68  if(i < 0x100 && bootrom_enabled)
69  return bootrom[i];
70 
71  if(DMA_pending && cpu_get_cycles() >= DMA_pending)
72  {
73  unsigned long elapsed;
74 
75  if(!DMA_copied)
76  {
77  memcpy(&mem[0xFE00], &mem[DMA_src], 0xA0);
78  DMA_copied = 1;
79  }
80 
81  elapsed = cpu_get_cycles() - DMA_pending;
82 
83  if(elapsed >= 160)
84  DMA_pending = 0;
85  else if(i < 0xFF00)
86  {
87  /* Reading from OAM during DMA always gives 0xFF */
88  if(i >= 0xFE00 && i <= 0xFEA0)
89  return 0xFF;
90 
91  /* !A ^ B checks if A and B are both 0 or both 1 */
92  if(!(((DMA_src >> 13) == 4) ^ ((i >> 13) == 4)))
93  return mem[0xFE00+elapsed];
94  }
95  }
96 
97  switch(i)
98  {
99  case 0xFF00: /* Joypad */
100  if(!joypad_select_buttons)
101  mask = sdl_get_buttons();
102  if(!joypad_select_directions)
103  mask = sdl_get_directions();
104  return 0xC0 | (0xF^mask) | (joypad_select_buttons | joypad_select_directions);
105  break;
106  case 0xFF04:
107  return timer_get_div();
108  break;
109  case 0xFF05:
110  return timer_get_counter();
111  break;
112  case 0xFF06:
113  return timer_get_modulo();
114  break;
115  case 0xFF07:
116  return timer_get_tac();
117  break;
118  case 0xFF0F:
119  return interrupt_get_IF();
120  break;
121  case 0xFF41:
122  return lcd_get_stat();
123  break;
124  case 0xFF44:
125  return lcd_get_line();
126  break;
127  case 0xFF45:
128  return lcd_get_ly_compare();
129  break;
130  case 0xFF4D: /* GBC speed switch */
131  return 0xFF;
132  break;
133  case 0xFFFF:
134  return interrupt_get_mask();
135  break;
136  }
137 
138  if(i >= 0xE000 && i <= 0xFDFF)
139  i -= 0x2000;
140 
141  if(i >= 0x8000 && i <= 0x9FFF && (lcd_get_stat() & 3) == 3)
142  return 0xFF;
143 
144  return mem[i];
145 }
146 
147 unsigned short mem_get_word(unsigned short i)
148 {
149  return mem_get_byte(i) | (mem_get_byte(i+1)<<8);
150 }
151 
152 void mem_write_byte(unsigned short d, unsigned char i)
153 {
154  unsigned int filtered = 0;
155 
156  if(DMA_pending && DMA_pending <= cpu_get_cycles())
157  {
158  long elapsed;
159 
160  if(!DMA_copied)
161  {
162  memcpy(&mem[0xFE00], &mem[DMA_src], 0xA0);
163  DMA_copied = 1;
164  }
165 
166  elapsed = cpu_get_cycles() - DMA_pending;
167 
168  if(elapsed >= 160)
169  DMA_pending = 0;
170  else if(d >= 0xFE00 && d <= 0xFEA0)
171  return;
172 
173  else if(!(((DMA_src >> 13) == 4) ^ ((d >> 13) == 4)))
174  return;
175  }
176 
177  switch(rom_get_mapper())
178  {
179  case NROM:
180  if(d < 0x8000)
181  filtered = 1;
182  break;
183  case MBC2:
184  case MBC3:
185  case MBC5:
186  filtered = MBC3_write_byte(d, i);
187  break;
188  case MBC1:
189  filtered = MBC1_write_byte(d, i);
190  break;
191  }
192 
193  if(filtered)
194  return;
195 
196  switch(d)
197  {
198  case 0xFF00: /* Joypad */
199  joypad_select_buttons = i&0x20;
200  joypad_select_directions = i&0x10;
201  break;
202  case 0xFF01: /* Link port data */
203  break;
204  case 0xFF04:
205  timer_set_div(i);
206  break;
207  case 0xFF05:
208  timer_set_counter(i);
209  break;
210  case 0xFF06:
211  timer_set_modulo(i);
212  break;
213  case 0xFF07:
214  timer_set_tac(i);
215  break;
216  case 0xFF0F:
217  interrupt_set_IF(i);
218  break;
219  case 0xFF40:
220  lcd_write_control(i);
221  break;
222  case 0xFF41:
223  lcd_write_stat(i);
224  break;
225  case 0xFF42:
226  lcd_write_scroll_y(i);
227  break;
228  case 0xFF43:
229  lcd_write_scroll_x(i);
230  break;
231  case 0xFF45:
232  lcd_set_ly_compare(i);
233  break;
234  case 0xFF46: /* OAM DMA */
235  /* This is the dead cycle where OAM DMA is busy, can't restart */
236  if(DMA_pending == cpu_get_cycles())
237  break;
238 
239  /* Start or restart OAM DMA */
240  DMA_pending = cpu_get_cycles()+2;
241  DMA_src = i * 0x100;
242  DMA_copied = 0;
243  break;
244  case 0xFF47:
245  lcd_write_bg_palette(i);
246  break;
247  case 0xFF48:
248  lcd_write_spr_palette1(i);
249  break;
250  case 0xFF49:
251  lcd_write_spr_palette2(i);
252  break;
253  case 0xFF4A:
254  lcd_set_window_y(i);
255  break;
256  case 0xFF4B:
257  lcd_set_window_x(i);
258  break;
259  case 0xFF50:
260  bootrom_enabled = 0;
261  break;
262  case 0xFFFF:
263  interrupt_set_mask(i);
264  return;
265  break;
266  }
267 
268 #ifndef DEBUG
269  if(d > 0x8000 && d < 0x9FFF && (lcd_get_stat() & 3) == 3)
270  return;
271 #endif
272 
273  /* RAM mirror */
274  if(d >= 0xE000 && d <= 0xFDFF)
275  d -= 0x2000;
276 
277  mem[d] = i;
278 }
279 
280 void mem_write_word(unsigned short d, unsigned short i)
281 {
282  mem_write_byte(d, i&0xFF);
283  mem_write_byte(d+1, i>>8);
284 }
285 
286 void mem_init(void)
287 {
288  unsigned char *bytes = rom_getbytes();
289 
290  mem = calloc(1, 0x10000);
291 
292  memcpy(&mem[0x0000], &bytes[0x0000], 0x4000);
293  memcpy(&mem[0x4000], &bytes[0x4000], 0x4000);
294 
295  mem[0xFF02] = 0x7E;
296  mem[0xFF10] = 0x80;
297  mem[0xFF11] = 0xBF;
298  mem[0xFF12] = 0xF3;
299  mem[0xFF14] = 0xBF;
300  mem[0xFF16] = 0x3F;
301  mem[0xFF19] = 0xBF;
302  mem[0xFF1A] = 0x7F;
303  mem[0xFF1B] = 0xFF;
304  mem[0xFF1C] = 0x9F;
305  mem[0xFF1E] = 0xBF;
306  mem[0xFF20] = 0xFF;
307  mem[0xFF23] = 0xBF;
308  mem[0xFF24] = 0x77;
309  mem[0xFF25] = 0xF3;
310  mem[0xFF26] = 0xF1;
311  mem[0xFF40] = 0x91;
312  mem[0xFF47] = 0xFC;
313  mem[0xFF48] = 0xFF;
314  mem[0xFF49] = 0xFF;
315 }
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Definition: string.c:173