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(&regs, 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(&regs, 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