some work on PSP CLUT
[libpicofe.git] / psp / emu.c
CommitLineData
2951214e 1#include <sys/stat.h>
2#include <sys/types.h>
3#include <sys/syslimits.h> // PATH_MAX
4
703e4c7b 5#include <pspthreadman.h>
2b90fc61 6#include <pspdisplay.h>
db298784 7#include <psputils.h>
8#include <pspgu.h>
703e4c7b 9
10#include "psp.h"
11#include "menu.h"
12#include "emu.h"
13#include "../common/emu.h"
14#include "../common/lprintf.h"
2951214e 15#include "../../Pico/PicoInt.h"
16
703e4c7b 17#ifdef BENCHMARK
18#define OSD_FPS_X 220
19#else
20#define OSD_FPS_X 260
21#endif
22
2951214e 23char romFileName[PATH_MAX];
db298784 24unsigned char *PicoDraw2FB = (unsigned char *)VRAM_CACHED_STUFF + 8; // +8 to be able to skip border with 1 quadword..
2951214e 25int engineState;
26
703e4c7b 27static int combo_keys = 0, combo_acts = 0; // keys and actions which need button combos
28static unsigned int noticeMsgTime = 0;
29int reset_timing = 0; // do we need this?
30
31
32static void blit(const char *fps, const char *notice);
33static void clearArea(int full);
2951214e 34
35void emu_noticeMsgUpdated(void)
36{
703e4c7b 37 noticeMsgTime = sceKernelGetSystemTimeLow();
2951214e 38}
39
40void emu_getMainDir(char *dst, int len)
41{
703e4c7b 42 if (len > 0) *dst = 0;
2951214e 43}
44
703e4c7b 45static void emu_msg_cb(const char *msg)
2951214e 46{
703e4c7b 47 void *fb = psp_video_get_active_fb();
48
49 memset32((int *)((char *)fb + 512*264*2), 0, 512*8*2/4);
50 emu_textOut16(4, 264, msg);
51 noticeMsgTime = sceKernelGetSystemTimeLow() - 2000000;
52
53 /* assumption: emu_msg_cb gets called only when something slow is about to happen */
54 reset_timing = 1;
2951214e 55}
56
703e4c7b 57void emu_stateCb(const char *str)
2951214e 58{
703e4c7b 59 clearArea(0);
60 blit("", str);
2951214e 61}
62
703e4c7b 63static void emu_msg_tray_open(void)
2951214e 64{
703e4c7b 65 strcpy(noticeMsg, "CD tray opened");
66 noticeMsgTime = sceKernelGetSystemTimeLow();
2951214e 67}
68
703e4c7b 69
2951214e 70void emu_Init(void)
71{
72 // make dirs for saves, cfgs, etc.
73 mkdir("mds", 0777);
74 mkdir("srm", 0777);
75 mkdir("brm", 0777);
76 mkdir("cfg", 0777);
77
78 PicoInit();
703e4c7b 79 PicoMessage = emu_msg_cb;
80 PicoMCDopenTray = emu_msg_tray_open;
81 PicoMCDcloseTray = menu_loop_tray;
2951214e 82}
83
84void emu_Deinit(void)
85{
86 // save SRAM
703e4c7b 87 if ((currentConfig.EmuOpt & 1) && SRam.changed) {
2951214e 88 emu_SaveLoadGame(0, 1);
89 SRam.changed = 0;
90 }
91
92 if (!(currentConfig.EmuOpt & 0x20)) {
93 FILE *f = fopen(PicoConfigFile, "r+b");
94 if (!f) emu_WriteConfig(0);
95 else {
96 // if we already have config, reload it, except last ROM
97 fseek(f, sizeof(currentConfig.lastRomFile), SEEK_SET);
98 fread(&currentConfig.EmuOpt, 1, sizeof(currentConfig) - sizeof(currentConfig.lastRomFile), f);
99 fseek(f, 0, SEEK_SET);
100 fwrite(&currentConfig, 1, sizeof(currentConfig), f);
101 fflush(f);
102 fclose(f);
103 }
104 }
703e4c7b 105
2951214e 106 PicoExit();
107}
108
703e4c7b 109void emu_setDefaultConfig(void)
110{
111 memset(&currentConfig, 0, sizeof(currentConfig));
112 currentConfig.lastRomFile[0] = 0;
113 currentConfig.EmuOpt = 0x1f | 0x680; // | confirm_save, cd_leds, 16bit rend
114 currentConfig.PicoOpt = 0x07 | 0xc00; // | cd_pcm, cd_cdda
115 currentConfig.PsndRate = 22050;
116 currentConfig.PicoRegion = 0; // auto
117 currentConfig.PicoAutoRgnOrder = 0x184; // US, EU, JP
118 currentConfig.Frameskip = -1; // auto
119 currentConfig.volume = 50;
2b90fc61 120 currentConfig.CPUclock = 222;
703e4c7b 121 currentConfig.KeyBinds[ 4] = 1<<0; // SACB RLDU
122 currentConfig.KeyBinds[ 6] = 1<<1;
123 currentConfig.KeyBinds[ 7] = 1<<2;
124 currentConfig.KeyBinds[ 5] = 1<<3;
125 currentConfig.KeyBinds[14] = 1<<4;
126 currentConfig.KeyBinds[13] = 1<<5;
127 currentConfig.KeyBinds[15] = 1<<6;
128 currentConfig.KeyBinds[ 3] = 1<<7;
129 currentConfig.KeyBinds[23] = 1<<26; // switch rend
130 currentConfig.KeyBinds[ 8] = 1<<27; // save state
131 currentConfig.KeyBinds[ 9] = 1<<28; // load state
132 currentConfig.PicoCDBuffers = 0;
133 currentConfig.scaling = 0;
134}
135
136
db298784 137static unsigned short __attribute__((aligned(16))) localPal[0x100];
138
139struct Vertex
140{
141 short u,v;
142 short x,y,z;
143};
144
145static void EmuScanPrepare(void)
146{
147 HighCol = VRAM_STUFF;
148
149#if 0
150 sceGuSync(0,0); // sync with prev
151 sceGuStart(GU_DIRECT, guCmdList);
152// sceGuDispBuffer(480, 272, psp_screen == VRAM_FB0 ? VRAMOFFS_FB1 : VRAMOFFS_FB0, 512);
153 sceGuDrawBuffer(GU_PSM_5650, psp_screen == VRAM_FB0 ? VRAMOFFS_FB0 : VRAMOFFS_FB1, 512); // point to back fb?
154 sceGuFinish();
155#endif
156}
157
703e4c7b 158static int EmuScan16(unsigned int num, void *sdata)
159{
db298784 160// struct Vertex* vertices;
161
703e4c7b 162 if (!(Pico.video.reg[1]&8)) num += 8;
db298784 163 //DrawLineDest = (unsigned short *) psp_screen + 512*(num+1);
164 HighCol = (unsigned char *)psp_screen + num*512;
165
166#if 0
167 sceGuSync(0,0); // sync with prev
168 sceGuStart(GU_DIRECT, guCmdList);
169
170 if (Pico.m.dirtyPal) {
171 int i, *dpal = (void *)localPal, *spal = (int *)Pico.cram;
172 Pico.m.dirtyPal = 0;
173 for (i = 0x3f/2; i >= 0; i--)
174 dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);
703e4c7b 175
db298784 176 sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
177 }
178
179 // setup CLUT texture
180
181// sceGuClutMode(GU_PSM_5650,0,0xff,0);
182// sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
183// sceGuTexMode(GU_PSM_T8,0,0,0); // 8-bit image
184// sceGuTexImage(0,512,1/*512*/,512,VRAM_STUFF);
185// sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB);
186// sceGuTexFilter(GU_LINEAR,GU_LINEAR);
187// sceGuTexScale(1.0f,1.0f);
188// sceGuTexOffset(0.0f,0.0f);
189// sceGuAmbientColor(0xffffffff);
190
191 // render sprite
192
193// sceGuColor(0xffffffff);
194 vertices = (struct Vertex*)sceGuGetMemory(2 * sizeof(struct Vertex));
195 vertices[0].u = 0; vertices[0].v = 0;
196 vertices[0].x = 0; vertices[0].y = num; vertices[0].z = 0;
197 vertices[1].u = 320; vertices[1].v = 512;
198 vertices[1].x = 320; vertices[1].y = num+1; vertices[1].z = 0;
199 //sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices);
200
201 sceGuFinish();
202#endif
703e4c7b 203 return 0;
204}
205
db298784 206
207static void draw2_clut(void)
208{
209 struct Vertex* vertices;
210 int x;
211
212 sceKernelDcacheWritebackAll(); // for PicoDraw2FB
213
214 sceGuSync(0,0); // sync with prev
215 sceGuStart(GU_DIRECT, guCmdList);
216// sceGuDispBuffer(480, 272, psp_screen == VRAM_FB0 ? VRAMOFFS_FB1 : VRAMOFFS_FB0, 512);
217 sceGuDrawBuffer(GU_PSM_5650, psp_screen == VRAM_FB0 ? VRAMOFFS_FB0 : VRAMOFFS_FB1, 512); // point to back fb?
218
219 if (Pico.m.dirtyPal) {
220 int i, *dpal = (void *)localPal, *spal = (int *)Pico.cram;
221 Pico.m.dirtyPal = 0;
222 for (i = 0x3f/2; i >= 0; i--)
223 dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);
224
225 sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
226 }
227
228 #define SLICE_WIDTH 32
229
230 for (x = 0; x < 320; x += SLICE_WIDTH)
231 {
232 // render sprite
233 vertices = (struct Vertex*)sceGuGetMemory(2 * sizeof(struct Vertex));
234 vertices[0].u = vertices[0].x = x;
235 vertices[0].v = vertices[0].y = 0;
236 vertices[0].z = 0;
237 vertices[1].u = vertices[1].x = x + SLICE_WIDTH;
238 vertices[1].v = vertices[1].y = 224;
239 vertices[1].z = 0;
240 sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices);
241 }
242
243 sceGuFinish();
244}
245
246
247
703e4c7b 248static int EmuScan8(unsigned int num, void *sdata)
249{
250 // draw like the fast renderer
251 // TODO?
252 //if (!(Pico.video.reg[1]&8)) num += 8;
253 //HighCol = gfx_buffer + 328*(num+1);
254
255 return 0;
256}
257
258static void osd_text(int x, const char *text)
259{
260 int len = strlen(text) * 8 / 2;
261 int *p, h;
262 for (h = 0; h < 8; h++) {
263 p = (int *) ((unsigned short *) psp_screen+x+512*(264+h));
264 p = (int *) ((int)p & ~3); // align
265 memset32(p, 0, len);
266 }
267 emu_textOut16(x, 264, text);
268}
269
270
271static void cd_leds(void)
272{
273 static int old_reg = 0;
274 unsigned int col_g, col_r, *p;
275
276 if (!((Pico_mcd->s68k_regs[0] ^ old_reg) & 3)) return; // no change
277 old_reg = Pico_mcd->s68k_regs[0];
278
279 p = (unsigned int *)((short *)psp_screen + 512*2+4+2);
280 col_g = (old_reg & 2) ? 0x06000600 : 0;
281 col_r = (old_reg & 1) ? 0xc000c000 : 0;
282 *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 512/2 - 12/2;
283 *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 512/2 - 12/2;
284 *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r;
285}
286
287
703e4c7b 288static void blit(const char *fps, const char *notice)
289{
290 int emu_opt = currentConfig.EmuOpt;
291
703e4c7b 292 if (PicoOpt&0x10)
293 {
db298784 294#if 1
295 draw2_clut();
296#else
297 extern void amips_clut(unsigned short *dst, unsigned char *src, unsigned short *pal, int count);
298 int i; // , lines_flags = 224;
299 unsigned short *pd = psp_screen;
300 unsigned char *ps = PicoDraw2FB+328*8+8;
703e4c7b 301 // 8bit fast renderer
302 if (Pico.m.dirtyPal) {
db298784 303 int *dpal = (void *)localPal;
304 int *spal = (int *)Pico.cram;
703e4c7b 305 Pico.m.dirtyPal = 0;
db298784 306 for (i = 0x3f/2; i >= 0; i--)
307 dpal[i] = ((spal[i]&0x000f000f)<< 1)|((spal[i]&0x00f000f0)<<3)|((spal[i]&0x0f000f00)<<4);
703e4c7b 308 }
db298784 309 // if (!(Pico.video.reg[12]&1)) lines_flags|=0x10000;
310 // if (currentConfig.EmuOpt&0x4000)
311 // lines_flags|=0x40000; // (Pico.m.frame_count&1)?0x20000:0x40000;
312 //vidCpy8to16((unsigned short *)giz_screen+321*8, PicoDraw2FB+328*8, localPal, lines_flags);
313 for (i = 224; i > 0; i--, pd+=512, ps+=328)
314 amips_clut(pd, ps, localPal, 320);
315#endif
703e4c7b 316 }
db298784 317#if 0
703e4c7b 318 else if (!(emu_opt&0x80))
319 {
320 int lines_flags;
321 // 8bit accurate renderer
322 if (Pico.m.dirtyPal) {
323 Pico.m.dirtyPal = 0;
324 vidConvCpyRGB565(localPal, Pico.cram, 0x40);
325 if (Pico.video.reg[0xC]&8) { // shadow/hilight mode
326 //vidConvCpyRGB32sh(localPal+0x40, Pico.cram, 0x40);
327 //vidConvCpyRGB32hi(localPal+0x80, Pico.cram, 0x40); // TODO?
328 blockcpy(localPal+0xc0, localPal+0x40, 0x40*2);
329 localPal[0xc0] = 0x0600;
330 localPal[0xd0] = 0xc000;
331 localPal[0xe0] = 0x0000; // reserved pixels for OSD
332 localPal[0xf0] = 0xffff;
333 }
334 /* no support
335 else if (rendstatus & 0x20) { // mid-frame palette changes
336 vidConvCpyRGB565(localPal+0x40, HighPal, 0x40);
337 vidConvCpyRGB565(localPal+0x80, HighPal+0x40, 0x40);
338 } */
339 }
340 lines_flags = (Pico.video.reg[1]&8) ? 240 : 224;
341 if (!(Pico.video.reg[12]&1)) lines_flags|=0x10000;
342 if (currentConfig.EmuOpt&0x4000)
343 lines_flags|=0x40000; // (Pico.m.frame_count&1)?0x20000:0x40000;
344 vidCpy8to16((unsigned short *)giz_screen+321*8, PicoDraw2FB+328*8, localPal, lines_flags);
345 }
346#endif
347
348 if (notice || (emu_opt & 2)) {
349 if (notice) osd_text(4, notice);
350 if (emu_opt & 2) osd_text(OSD_FPS_X, fps);
351 }
352
353 if ((emu_opt & 0x400) && (PicoMCD & 1))
354 cd_leds();
355
db298784 356 sceGuSync(0,0);
703e4c7b 357 psp_video_flip(0);
358}
359
360// clears whole screen or just the notice area (in all buffers)
361static void clearArea(int full)
362{
363 if (full) {
364 memset32(psp_screen, 0, 512*272*2/4);
365 psp_video_flip(0);
366 memset32(psp_screen, 0, 512*272*2/4);
367 } else {
368 void *fb = psp_video_get_active_fb();
369 memset32((int *)((char *)psp_screen + 512*264*2), 0, 512*8*2/4);
370 memset32((int *)((char *)fb + 512*264*2), 0, 512*8*2/4);
371 }
372}
373
374static void vidResetMode(void)
375{
db298784 376 // setup GU
377 sceGuSync(0,0); // sync with prev
378 sceGuStart(GU_DIRECT, guCmdList);
379
380 sceGuClutMode(GU_PSM_5650,0,0xff,0);
381 //sceGuClutLoad((256/8), localPal); // upload 32*8 entries (256)
382 sceGuTexMode(GU_PSM_T8,0,0,0); // 8-bit image
383 sceGuTexFunc(GU_TFX_REPLACE,GU_TCC_RGB);
384 sceGuTexFilter(GU_LINEAR,GU_LINEAR);
385 sceGuTexScale(1.0f,1.0f);
386 sceGuTexOffset(0.0f,0.0f);
387 sceGuAmbientColor(0xffffffff);
388 sceGuColor(0xffffffff);
389
390
703e4c7b 391 if (PicoOpt&0x10) {
db298784 392 sceGuTexImage(0,512,512,512,(char *)VRAM_STUFF + 8*512+16);
393
703e4c7b 394 } else if (currentConfig.EmuOpt&0x80) {
db298784 395 PicoDrawSetColorFormat(/*1*/-1);
703e4c7b 396 PicoScan = EmuScan16;
db298784 397
398 sceGuTexImage(0,512,1/*512*/,512,VRAM_STUFF);
399
703e4c7b 400 } else {
401 PicoDrawSetColorFormat(-1);
402 PicoScan = EmuScan8;
403 }
404 if ((PicoOpt&0x10) || !(currentConfig.EmuOpt&0x80)) {
405 // setup pal for 8-bit modes
406 localPal[0xc0] = 0x0600;
407 localPal[0xd0] = 0xc000;
408 localPal[0xe0] = 0x0000; // reserved pixels for OSD
409 localPal[0xf0] = 0xffff;
410 }
411 Pico.m.dirtyPal = 1;
412
db298784 413 sceGuFinish();
414 sceGuSync(0,0);
415
703e4c7b 416 clearArea(1);
417}
db298784 418/*
703e4c7b 419static void updateSound(int len)
420{
421 if (PicoOpt&8) len<<=1;
422
423 // TODO..
424}
db298784 425*/
703e4c7b 426
427static void SkipFrame(void)
428{
429 PicoSkipFrame=1;
430 PicoFrame();
431 PicoSkipFrame=0;
432}
433
434void emu_forcedFrame(void)
435{
436 int po_old = PicoOpt;
437 int eo_old = currentConfig.EmuOpt;
438
439 PicoOpt &= ~0x0010;
440 PicoOpt |= 0x4080; // soft_scale | acc_sprites
441 currentConfig.EmuOpt |= 0x80;
442
443 PicoDrawSetColorFormat(1);
444 PicoScan = EmuScan16;
db298784 445 EmuScanPrepare();
703e4c7b 446 Pico.m.dirtyPal = 1;
447 PicoFrameDrawOnly();
448
449 PicoOpt = po_old;
450 currentConfig.EmuOpt = eo_old;
451}
452
453
454static void RunEvents(unsigned int which)
455{
456 if (which & 0x1800) // save or load (but not both)
457 {
458 int do_it = 1;
459
460 if ( emu_checkSaveFile(state_slot) &&
461 (( (which & 0x1000) && (currentConfig.EmuOpt & 0x800)) || // load
462 (!(which & 0x1000) && (currentConfig.EmuOpt & 0x200))) ) // save
463 {
464 int keys;
465 blit("", (which & 0x1000) ? "LOAD STATE? (X=yes, O=no)" : "OVERWRITE SAVE? (X=yes, O=no)");
466 while( !((keys = psp_pad_read(1)) & (BTN_X|BTN_CIRCLE)) )
467 psp_msleep(50);
468 if (keys & BTN_CIRCLE) do_it = 0;
469 while( ((keys = psp_pad_read(1)) & (BTN_X|BTN_CIRCLE)) ) // wait for release
470 psp_msleep(50);
471 clearArea(0);
472 }
473
474 if (do_it)
475 {
476 osd_text(4, (which & 0x1000) ? "LOADING GAME" : "SAVING GAME");
477 PicoStateProgressCB = emu_stateCb;
478 emu_SaveLoadGame((which & 0x1000) >> 12, 0);
479 PicoStateProgressCB = NULL;
480 psp_msleep(0);
481 }
482
483 reset_timing = 1;
484 }
485 if (which & 0x0400) // switch renderer
486 {
487 if (PicoOpt&0x10) { PicoOpt&=~0x10; currentConfig.EmuOpt |= 0x80; }
488 else { PicoOpt|= 0x10; currentConfig.EmuOpt &= ~0x80; }
489
490 vidResetMode();
491
492 if (PicoOpt&0x10) {
493 strcpy(noticeMsg, " 8bit fast renderer");
494 } else if (currentConfig.EmuOpt&0x80) {
495 strcpy(noticeMsg, "16bit accurate renderer");
496 } else {
497 strcpy(noticeMsg, " 8bit accurate renderer");
498 }
499
500 noticeMsgTime = sceKernelGetSystemTimeLow();
501 }
502 if (which & 0x0300)
503 {
504 if(which&0x0200) {
505 state_slot -= 1;
506 if(state_slot < 0) state_slot = 9;
507 } else {
508 state_slot += 1;
509 if(state_slot > 9) state_slot = 0;
510 }
511 sprintf(noticeMsg, "SAVE SLOT %i [%s]", state_slot, emu_checkSaveFile(state_slot) ? "USED" : "FREE");
512 noticeMsgTime = sceKernelGetSystemTimeLow();
513 }
514}
515
516static void updateKeys(void)
517{
518 unsigned int keys, allActions[2] = { 0, 0 }, events;
519 static unsigned int prevEvents = 0;
520 int i;
521
522 keys = psp_pad_read(0);
2b90fc61 523 if (keys & PSP_CTRL_HOME)
524 sceDisplayWaitVblankStart();
525
703e4c7b 526 if (keys & BTN_SELECT)
527 engineState = PGS_Menu;
528
529 keys &= CONFIGURABLE_KEYS;
530
531 for (i = 0; i < 32; i++)
532 {
533 if (keys & (1 << i))
534 {
535 int pl, acts = currentConfig.KeyBinds[i];
536 if (!acts) continue;
537 pl = (acts >> 16) & 1;
538 if (combo_keys & (1 << i))
539 {
540 int u = i+1, acts_c = acts & combo_acts;
541 // let's try to find the other one
542 if (acts_c)
543 for (; u < 32; u++)
544 if ( (currentConfig.KeyBinds[u] & acts_c) && (keys & (1 << u)) ) {
545 allActions[pl] |= acts_c;
546 keys &= ~((1 << i) | (1 << u));
547 break;
548 }
549 // add non-combo actions if combo ones were not found
550 if (!acts_c || u == 32)
551 allActions[pl] |= acts & ~combo_acts;
552 } else {
553 allActions[pl] |= acts;
554 }
555 }
556 }
557
558 PicoPad[0] = (unsigned short) allActions[0];
559 PicoPad[1] = (unsigned short) allActions[1];
560
561 events = (allActions[0] | allActions[1]) >> 16;
562
563 // volume is treated in special way and triggered every frame
564 if ((events & 0x6000) && PsndOut != NULL)
565 {
566 int vol = currentConfig.volume;
567 if (events & 0x2000) {
568 if (vol < 100) vol++;
569 } else {
570 if (vol > 0) vol--;
571 }
572 // FrameworkAudio_SetVolume(vol, vol); // TODO
573 sprintf(noticeMsg, "VOL: %02i ", vol);
574 noticeMsgTime = sceKernelGetSystemTimeLow();
575 currentConfig.volume = vol;
576 }
577
578 events &= ~prevEvents;
579 if (events) RunEvents(events);
580 if (movie_data) emu_updateMovie();
581
582 prevEvents = (allActions[0] | allActions[1]) >> 16;
583}
584
585static void find_combos(void)
586{
587 int act, u;
588
589 // find out which keys and actions are combos
590 combo_keys = combo_acts = 0;
591 for (act = 0; act < 32; act++)
592 {
593 int keyc = 0;
594 if (act == 16 || act == 17) continue; // player2 flag
595 for (u = 0; u < 32; u++)
596 {
597 if (currentConfig.KeyBinds[u] & (1 << act)) keyc++;
598 }
599 if (keyc > 1)
600 {
601 // loop again and mark those keys and actions as combo
602 for (u = 0; u < 32; u++)
603 {
604 if (currentConfig.KeyBinds[u] & (1 << act)) {
605 combo_keys |= 1 << u;
606 combo_acts |= 1 << act;
607 }
608 }
609 }
610 }
611}
612
613
614static void simpleWait(unsigned int until)
615{
616 unsigned int tval;
617 int diff;
618
619 tval = sceKernelGetSystemTimeLow();
620 diff = (int)until - (int)tval;
621 if (diff >= 512 && diff < 100*1024)
622 sceKernelDelayThread(diff);
623}
624
625void emu_Loop(void)
626{
627 //static int PsndRate_old = 0, PicoOpt_old = 0, pal_old = 0;
628 char fpsbuff[24]; // fps count c string
629 unsigned int tval, tval_prev = 0, tval_thissec = 0; // timing
630 int frames_done = 0, frames_shown = 0, oldmodes = 0;
631 int target_fps, target_frametime, lim_time, tval_diff, i;
632 char *notice = NULL;
633
634 lprintf("entered emu_Loop()\n");
635
636 fpsbuff[0] = 0;
637
2b90fc61 638 if (currentConfig.CPUclock != psp_get_cpu_clock()) {
639 lprintf("setting cpu clock to %iMHz... ", currentConfig.CPUclock);
640 i = psp_set_cpu_clock(currentConfig.CPUclock);
641 lprintf(i ? "failed\n" : "done\n");
642 currentConfig.CPUclock = psp_get_cpu_clock();
643 }
644
703e4c7b 645 // make sure we are in correct mode
646 vidResetMode();
647 Pico.m.dirtyPal = 1;
648 oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;
649 find_combos();
650
651 // pal/ntsc might have changed, reset related stuff
652 target_fps = Pico.m.pal ? 50 : 60;
653 target_frametime = Pico.m.pal ? (1000000<<8)/50 : (1000000<<8)/60+1;
654 reset_timing = 1;
655
656 // prepare CD buffer
657 if (PicoMCD & 1) PicoCDBufferInit();
658
659 // prepare sound stuff
660 PsndOut = NULL;
661#if 0 // TODO
662 if (currentConfig.EmuOpt & 4)
663 {
664 int ret, snd_excess_add, stereo;
665 if (PsndRate != PsndRate_old || (PicoOpt&0x0b) != (PicoOpt_old&0x0b) || Pico.m.pal != pal_old) {
666 sound_rerate(Pico.m.frame_count ? 1 : 0);
667 }
668 stereo=(PicoOpt&8)>>3;
669 snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps;
670 snd_cbuf_samples = (PsndRate<<stereo) * 16 / target_fps;
671 lprintf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n",
672 PsndRate, PsndLen, snd_excess_add, stereo, Pico.m.pal);
673 ret = FrameworkAudio_Init(PsndRate, snd_cbuf_samples, stereo);
674 if (ret != 0) {
675 lprintf("FrameworkAudio_Init() failed: %i\n", ret);
676 sprintf(noticeMsg, "sound init failed (%i), snd disabled", ret);
677 noticeMsgTime = sceKernelGetSystemTimeLow();
678 currentConfig.EmuOpt &= ~4;
679 } else {
680 FrameworkAudio_SetVolume(currentConfig.volume, currentConfig.volume);
681 PicoWriteSound = updateSound;
682 snd_cbuff = FrameworkAudio_56448Buffer();
683 PsndOut = snd_cbuff + snd_cbuf_samples / 2; // start writing at the middle
684 snd_all_samples = 0;
685 PsndRate_old = PsndRate;
686 PicoOpt_old = PicoOpt;
687 pal_old = Pico.m.pal;
688 }
689 }
690#endif
691
692 // loop?
693 while (engineState == PGS_Running)
694 {
695 int modes;
696
697 tval = sceKernelGetSystemTimeLow();
698 if (reset_timing || tval < tval_prev) {
699 //stdbg("timing reset");
700 reset_timing = 0;
701 tval_thissec = tval;
702 frames_shown = frames_done = 0;
703 }
704
705 // show notice message?
706 if (noticeMsgTime) {
707 static int noticeMsgSum;
708 if (tval - noticeMsgTime > 2000000) { // > 2.0 sec
709 noticeMsgTime = 0;
710 clearArea(0);
711 notice = 0;
712 } else {
713 int sum = noticeMsg[0]+noticeMsg[1]+noticeMsg[2];
714 if (sum != noticeMsgSum) { clearArea(0); noticeMsgSum = sum; }
715 notice = noticeMsg;
716 }
717 }
718
719 // check for mode changes
720 modes = ((Pico.video.reg[12]&1)<<2)|(Pico.video.reg[1]&8);
721 if (modes != oldmodes) {
722 oldmodes = modes;
723 clearArea(1);
724 }
725
726 // second passed?
727 if (tval - tval_thissec >= 1000000)
728 {
729#ifdef BENCHMARK
730 static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];
731 if(++bench == 10) {
732 bench = 0;
733 bench_fps_s = bench_fps;
734 bf[bfp++ & 3] = bench_fps;
735 bench_fps = 0;
736 }
737 bench_fps += frames_shown;
738 sprintf(fpsbuff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);
739#else
740 if(currentConfig.EmuOpt & 2)
741 sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done);
742#endif
743 tval_thissec += 1000000;
744
745 if (currentConfig.Frameskip < 0) {
746 frames_done -= target_fps; if (frames_done < 0) frames_done = 0;
747 frames_shown -= target_fps; if (frames_shown < 0) frames_shown = 0;
748 if (frames_shown > frames_done) frames_shown = frames_done;
749 } else {
750 frames_done = frames_shown = 0;
751 }
752 }
753#ifdef PFRAMES
754 sprintf(fpsbuff, "%i", Pico.m.frame_count);
755#endif
756
757 tval_prev = tval;
758 lim_time = (frames_done+1) * target_frametime;
759 if (currentConfig.Frameskip >= 0) // frameskip enabled
760 {
761 for (i = 0; i < currentConfig.Frameskip; i++) {
762 updateKeys();
763 SkipFrame(); frames_done++;
764 if (PsndOut) { // do framelimitting if sound is enabled
765 int tval_diff;
766 tval = sceKernelGetSystemTimeLow();
767 tval_diff = (int)(tval - tval_thissec) << 8;
768 if (tval_diff < lim_time) // we are too fast
769 simpleWait(tval + ((lim_time - tval_diff)>>8));
770 }
771 lim_time += target_frametime;
772 }
773 }
774 else // auto frameskip
775 {
776 int tval_diff;
777 tval = sceKernelGetSystemTimeLow();
778 tval_diff = (int)(tval - tval_thissec) << 8;
779 if (tval_diff > lim_time)
780 {
781 // no time left for this frame - skip
782 if (tval_diff - lim_time >= (300000<<8)) {
783 /* something caused a slowdown for us (disk access? cache flush?)
784 * try to recover by resetting timing... */
785 reset_timing = 1;
786 continue;
787 }
788 updateKeys();
789 SkipFrame(); frames_done++;
790 continue;
791 }
792 }
793
794 updateKeys();
795
796 if (!(PicoOpt&0x10))
db298784 797 EmuScanPrepare();
703e4c7b 798
799 PicoFrame();
800
801 blit(fpsbuff, notice);
802
803 // check time
804 tval = sceKernelGetSystemTimeLow();
805 tval_diff = (int)(tval - tval_thissec) << 8;
806
807 if (currentConfig.Frameskip < 0 && tval_diff - lim_time >= (300000<<8)) // slowdown detection
808 reset_timing = 1;
809 else if (PsndOut != NULL || currentConfig.Frameskip < 0)
810 {
811 // sleep if we are still too fast
812 if (tval_diff < lim_time)
813 {
814 // we are too fast
815 simpleWait(tval + ((lim_time - tval_diff) >> 8));
816 }
817 }
818
819 frames_done++; frames_shown++;
820 }
821
822
823 if (PicoMCD & 1) PicoCDBufferFree();
824/*
825 if (PsndOut != NULL) {
826 PsndOut = snd_cbuff = NULL;
827 FrameworkAudio_Close();
828 }
829*/
830 // save SRAM
831 if ((currentConfig.EmuOpt & 1) && SRam.changed) {
832 emu_stateCb("Writing SRAM/BRAM..");
833 emu_SaveLoadGame(0, 1);
834 SRam.changed = 0;
835 }
836}
837
838
2951214e 839void emu_ResetGame(void)
840{
841 PicoReset(0);
703e4c7b 842 reset_timing = 1;
2951214e 843}
844