1 /*--------------------------------------------------
2 TGB Dual - Gameboy Emulator -
3 Copyright (C) 2001 Hii
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
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.
14
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
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 //-------------------------------------------------
21 // GB その他エミュレーション部/外部とのインターフェース
22 // Interface with external / other unit emulation GB
23
24 #include "gb.h"
25 #include <stdlib.h>
26
gb(renderer * ref,bool b_lcd,bool b_apu)27 gb::gb(renderer *ref,bool b_lcd,bool b_apu)
28 {
29 m_renderer=ref;
30
31 m_lcd=new lcd(this);
32 m_rom=new rom();
33 m_apu=new apu(this);// ROMより後に作られたし // I was made later than the ROM
34 m_mbc=new mbc(this);
35 m_cpu=new cpu(this);
36 m_cheat=new cheat(this);
37 target=NULL;
38
39 m_renderer->reset();
40 m_renderer->set_sound_renderer(b_apu?m_apu->get_renderer():NULL);
41
42 reset();
43
44 hook_ext=false;
45 use_gba=false;
46 }
47
~gb()48 gb::~gb()
49 {
50 m_renderer->set_sound_renderer(NULL);
51
52 delete m_mbc;
53 delete m_rom;
54 delete m_apu;
55 delete m_lcd;
56 delete m_cpu;
57 }
58
reset()59 void gb::reset()
60 {
61 regs.SC=0;
62 regs.DIV=0;
63 regs.TIMA=0;
64 regs.TMA=0;
65 regs.TAC=0;
66 regs.LCDC=0x91;
67 regs.STAT=0;
68 regs.SCY=0;
69 regs.SCX=0;
70 regs.LY=153;
71 regs.LYC=0;
72 regs.BGP=0xFC;
73 regs.OBP1=0xFF;
74 regs.OBP2=0xFF;
75 regs.WY=0;
76 regs.WX=0;
77 regs.IF=0;
78 regs.IE=0;
79
80 memset(&c_regs,0,sizeof(c_regs));
81
82 if (m_rom->get_loaded())
83 m_rom->get_info()->gb_type=(m_rom->get_rom()[0x143]&0x80)?(use_gba?4:3):1;
84
85 m_cpu->reset();
86 m_lcd->reset();
87 m_apu->reset();
88 m_mbc->reset();
89
90 now_frame=0;
91 skip=skip_buf=0;
92 re_render=0;
93 }
94
hook_extport(ext_hook * ext)95 void gb::hook_extport(ext_hook *ext)
96 {
97 hook_proc=*ext;
98 hook_ext=true;
99 }
100
unhook_extport()101 void gb::unhook_extport()
102 {
103 hook_ext=false;
104 }
105
set_skip(int frame)106 void gb::set_skip(int frame)
107 {
108 skip_buf=frame;
109 }
110
load_rom(byte * buf,int size,byte * ram,int ram_size)111 bool gb::load_rom(byte *buf,int size,byte *ram,int ram_size)
112 {
113 if (m_rom->load_rom(buf,size,ram,ram_size))
114 {
115 reset();
116 return true;
117 }
118 return false;
119 }
120
121 // savestate format matching the original TGB dual, pre-libretro port
serialize_legacy(serializer & s)122 void gb::serialize_legacy(serializer &s)
123 {
124 int tbl_ram[]={1,1,1,4,16,8};
125
126 s.process(&m_rom->get_info()->gb_type, sizeof(int));
127 bool gbc = m_rom->get_info()->gb_type >= 3; // GB: 1, SGB: 2, GBC: 3...
128
129 int cpu_dat[16]; // only used when gbc is true
130
131 if(gbc) {
132 s.process(m_cpu->get_ram(), 0x2000*4);
133 s.process(m_cpu->get_vram(), 0x2000*2);
134 } else {
135 s.process(m_cpu->get_ram(), 0x2000);
136 s.process(m_cpu->get_vram(), 0x2000);
137 }
138 s.process(m_rom->get_sram(), tbl_ram[m_rom->get_info()->ram_size]*0x2000);
139 s.process(m_cpu->get_oam(), 0xA0);
140 s.process(m_cpu->get_stack(), 0x80);
141
142 int rom_page = (m_mbc->get_rom()-m_rom->get_rom())/0x4000;
143 int ram_page = (m_mbc->get_sram()-m_rom->get_sram())/0x2000;
144 s.process(&rom_page, sizeof(int));
145 s.process(&ram_page, sizeof(int));
146 m_mbc->set_page(rom_page, ram_page); // hackish, but should work.
147 // basically, if we're serializing to count or save, the set_page
148 // should have no effect assuming the calculations above are correct.
149 // tl;dr: "if it's good enough for saving, it's good enough for loading"
150
151 if(gbc) {
152 m_cpu->save_state(cpu_dat);
153
154 s.process(cpu_dat+0, 2*sizeof(int)); //int_page, vram_page
155 /* s.process(cpu_dat+1, sizeof(int)); ^ just serialize both in one go */
156 }
157
158 s.process(m_cpu->get_regs(), sizeof(cpu_regs)); // cpu_reg
159 s.process(®s, sizeof(gb_regs)); //sys_reg
160
161 if(gbc) {
162 s.process(&c_regs, sizeof(gbc_regs)); //col_reg
163 s.process(m_lcd->get_pal(0), sizeof(word)*8*4*2); //palette
164 }
165
166 int halt = !! (*m_cpu->get_halt());
167 s.process(&halt, sizeof(int));
168 (*m_cpu->get_halt()) = !! halt; // same errata as above
169
170 // Originally the number of clocks until serial communication expires
171 int dmy = 0;
172 s.process(&dmy, sizeof(int));
173
174 int mbc_dat = m_mbc->get_state();
175 s.process(&mbc_dat, sizeof(int)); //MBC
176 m_mbc->set_state(mbc_dat);
177
178 int ext_is = !! m_mbc->is_ext_ram();
179 s.process(&ext_is, sizeof(int));
180 m_mbc->set_ext_is(!! ext_is);
181
182 if(gbc) {
183 // Many additional specifications
184 /* i think this is inefficient...
185 s.process(cpu_dat+2, sizeof(int));
186
187 s.process(cpu_dat+3, sizeof(int));
188 s.process(cpu_dat+4, sizeof(int));
189 s.process(cpu_dat+5, sizeof(int));
190 s.process(cpu_dat+6, sizeof(int));
191
192 s.process(cpu_dat+7, sizeof(int));
193 */
194 s.process(cpu_dat+2, 6*sizeof(int));
195 m_cpu->restore_state(cpu_dat); // same errata as above
196 }
197
198 // Added ver 1.1
199 s.process(m_apu->get_stat(), sizeof(apu_stat));
200 s.process(m_apu->get_mem(), 0x30);
201 s.process(m_apu->get_stat_cpy(), sizeof(apu_stat));
202
203 byte resurved[256];
204 memset(resurved, 0, 256);
205 s.process(resurved, 256); // Reserved for future use
206 }
207
208
209 // TODO: put 'serialize' in other classes (cpu, mbc, ...) and call it from here.
serialize_firstrev(serializer & s)210 void gb::serialize_firstrev(serializer &s)
211 {
212 int tbl_ram[]={1,1,1,4,16,8};
213
214 s.process(&m_rom->get_info()->gb_type, sizeof(int));
215 bool gbc = m_rom->get_info()->gb_type >= 3; // GB: 1, SGB: 2, GBC: 3...
216
217 int cpu_dat[16];
218
219 if(gbc) {
220 s.process(m_cpu->get_ram(), 0x2000*4);
221 s.process(m_cpu->get_vram(), 0x2000*2);
222 } else {
223 s.process(m_cpu->get_ram(), 0x2000);
224 s.process(m_cpu->get_vram(), 0x2000);
225 }
226 s.process(m_rom->get_sram(), tbl_ram[m_rom->get_info()->ram_size]*0x2000);
227 s.process(m_cpu->get_oam(), 0xA0);
228 s.process(m_cpu->get_stack(), 0x80);
229
230 int rom_page = (m_mbc->get_rom() - m_rom->get_rom()) / 0x4000;
231 int ram_page = (m_mbc->get_sram() - m_rom->get_sram()) / 0x2000;
232 s.process(&rom_page, sizeof(int)); // rom_page
233 s.process(&ram_page, sizeof(int)); // ram_page
234 m_mbc->set_page(rom_page, ram_page); // hackish, but should work.
235 // basically, if we're serializing to count or save, the set_page
236 // should have no effect assuming the calculations above are correct.
237 // tl;dr: "if it's good enough for saving, it's good enough for loading"
238
239 if(true || gbc) { // why not for normal gb as well?
240 m_cpu->save_state(cpu_dat);
241 m_cpu->save_state_ex(cpu_dat+8);
242 s.process(cpu_dat, 12*sizeof(int));
243 m_cpu->restore_state(cpu_dat); // same errata as above
244 m_cpu->restore_state_ex(cpu_dat+8);
245 }
246
247 s.process(m_cpu->get_regs(), sizeof(cpu_regs)); // cpu_reg
248 s.process(®s, sizeof(gb_regs)); //sys_reg
249
250 if(gbc) {
251 s.process(&c_regs, sizeof(gbc_regs)); //col_reg
252 s.process(m_lcd->get_pal(0), sizeof(word)*8*4*2); //palette
253 }
254
255 s.process(m_cpu->get_halt(), sizeof(bool));
256
257 int mbc_dat = m_mbc->get_state();
258 s.process(&mbc_dat, sizeof(int)); //MBC
259 m_mbc->set_state(mbc_dat);
260
261 bool ext_is = m_mbc->is_ext_ram();
262 s.process(&ext_is, sizeof(bool));
263 m_mbc->set_ext_is(ext_is);
264
265 // Added ver 1.1
266 s.process(m_apu->get_stat(), sizeof(apu_stat));
267 s.process(m_apu->get_mem(), 0x30);
268 s.process(m_apu->get_stat_cpy(), sizeof(apu_stat));
269 }
270
serialize(serializer & s)271 void gb::serialize(serializer &s)
272 {
273 s_VAR(regs);
274 s_VAR(c_regs);
275
276 m_rom->serialize(s);
277 m_cpu->serialize(s);
278 m_mbc->serialize(s);
279 m_lcd->serialize(s);
280 m_apu->serialize(s);
281 }
282
get_state_size(void)283 size_t gb::get_state_size(void)
284 {
285 size_t ret = 0;
286 serializer s(&ret, serializer::COUNT);
287 serialize(s);
288 return ret;
289 }
290
save_state_mem(void * buf)291 void gb::save_state_mem(void *buf)
292 {
293 serializer s(buf, serializer::SAVE_BUF);
294 serialize(s);
295 }
296
restore_state_mem(void * buf)297 void gb::restore_state_mem(void *buf)
298 {
299 serializer s(buf, serializer::LOAD_BUF);
300 serialize(s);
301 }
302
refresh_pal()303 void gb::refresh_pal()
304 {
305 for (int i=0;i<64;i++)
306 m_lcd->get_mapped_pal(i>>2)[i&3]=m_renderer->map_color(m_lcd->get_pal(i>>2)[i&3]);
307 }
308
run()309 void gb::run()
310 {
311 if (m_rom->get_loaded()){
312 if (regs.LCDC&0x80){ // LCDC 起動時 // Startup LCDC
313 regs.LY=(regs.LY+1)%154;
314
315 regs.STAT&=0xF8;
316 if (regs.LYC==regs.LY){
317 regs.STAT|=4;
318 if (regs.STAT&0x40)
319 m_cpu->irq(INT_LCDC);
320 }
321 if (regs.LY==0){
322 m_renderer->refresh();
323 if (now_frame>=skip){
324 m_renderer->render_screen((byte*)vframe,160,144,16);
325 now_frame=0;
326 }
327 else
328 now_frame++;
329 m_lcd->clear_win_count();
330 skip=skip_buf;
331 }
332 if (regs.LY>=144){ // VBlank 期間中 // During VBlank
333 regs.STAT|=1;
334 if (regs.LY==144){
335 m_cpu->exec(72);
336 m_cpu->irq(INT_VBLANK);
337 if (regs.STAT&0x10)
338 m_cpu->irq(INT_LCDC);
339 m_cpu->exec(456-80);
340 }
341 else if (regs.LY==153){
342 m_cpu->exec(80);
343 regs.LY=0;
344 // 前のラインのかなり早目から0になるようだ。
345 // It's pretty early to be 0 from the previous line.
346 m_cpu->exec(456-80);
347 regs.LY=153;
348 }
349 else
350 m_cpu->exec(456);
351 }
352 else{ // VBlank 期間外 // Period outside VBlank
353 regs.STAT|=2;
354 if (regs.STAT&0x20)
355 m_cpu->irq(INT_LCDC);
356 m_cpu->exec(80); // state=2
357 regs.STAT|=3;
358 m_cpu->exec(169); // state=3
359
360 if (m_cpu->dma_executing){ // HBlank DMA
361 if (m_cpu->b_dma_first){
362 m_cpu->dma_dest_bank=m_cpu->vram_bank;
363 if (m_cpu->dma_src<0x4000)
364 m_cpu->dma_src_bank=m_rom->get_rom();
365 else if (m_cpu->dma_src<0x8000)
366 m_cpu->dma_src_bank=m_mbc->get_rom();
367 else if (m_cpu->dma_src>=0xA000&&m_cpu->dma_src<0xC000)
368 m_cpu->dma_src_bank=m_mbc->get_sram()-0xA000;
369 else if (m_cpu->dma_src>=0xC000&&m_cpu->dma_src<0xD000)
370 m_cpu->dma_src_bank=m_cpu->ram-0xC000;
371 else if (m_cpu->dma_src>=0xD000&&m_cpu->dma_src<0xE000)
372 m_cpu->dma_src_bank=m_cpu->ram_bank-0xD000;
373 else m_cpu->dma_src_bank=NULL;
374 m_cpu->b_dma_first=false;
375 }
376 memcpy(m_cpu->dma_dest_bank+(m_cpu->dma_dest&0x1ff0),m_cpu->dma_src_bank+m_cpu->dma_src,16);
377 // fprintf(m_cpu->file,"%03d : dma exec %04X -> %04X rest %d\n",regs.LY,m_cpu->dma_src,m_cpu->dma_dest,m_cpu->dma_rest);
378
379 m_cpu->dma_src+=16;
380 m_cpu->dma_src&=0xfff0;
381 m_cpu->dma_dest+=16;
382 m_cpu->dma_dest&=0xfff0;
383 m_cpu->dma_rest--;
384 if (!m_cpu->dma_rest)
385 m_cpu->dma_executing=false;
386
387 // m_cpu->total_clock+=207*(m_cpu->speed?2:1);
388 // m_cpu->sys_clock+=207*(m_cpu->speed?2:1);
389 // m_cpu->div_clock+=207*(m_cpu->speed?2:1);
390 // regs.STAT|=3;
391
392 if (now_frame>=skip)
393 m_lcd->render(vframe,regs.LY);
394
395 regs.STAT&=0xfc;
396 m_cpu->exec(207); // state=3
397 }
398 else{
399 /* if (m_lcd->get_sprite_count()){
400 if (m_lcd->get_sprite_count()>=10){
401 m_cpu->exec(129);
402 if ((regs.STAT&0x08))
403 m_cpu->irq(INT_LCDC);
404 regs.STAT&=0xfc;
405 if (now_frame>=skip)
406 m_lcd->render(vframe,regs.LY);
407 m_cpu->exec(78); // state=0
408 }
409 else{
410 m_cpu->exec(129*m_lcd->get_sprite_count()/10);
411 if ((regs.STAT&0x08))
412 m_cpu->irq(INT_LCDC);
413 regs.STAT&=0xfc;
414 if (now_frame>=skip)
415 m_lcd->render(vframe,regs.LY);
416 m_cpu->exec(207-(129*m_lcd->get_sprite_count()/10)); // state=0
417 }
418 }
419 else{
420 */ regs.STAT&=0xfc;
421 if (now_frame>=skip)
422 m_lcd->render(vframe,regs.LY);
423 if ((regs.STAT&0x08))
424 m_cpu->irq(INT_LCDC);
425 m_cpu->exec(207); // state=0
426 // }
427 }
428 }
429 }
430 else{ // LCDC 停止時 // LCDC is stopped
431 regs.LY=0;
432 // regs.LY=(regs.LY+1)%154;
433 re_render++;
434 if (re_render>=154){
435 memset(vframe,0xff,160*144*2);
436 m_renderer->refresh();
437 if (now_frame>=skip){
438 m_renderer->render_screen((byte*)vframe,160,144,16);
439 now_frame=0;
440 }
441 else
442 now_frame++;
443 m_lcd->clear_win_count();
444 re_render=0;
445 }
446 regs.STAT&=0xF8;
447 m_cpu->exec(456);
448 }
449 }
450 }
451