diff options
-rw-r--r-- | backends/ps2/DmaPipe.cpp | 37 | ||||
-rw-r--r-- | backends/ps2/DmaPipe.h | 3 | ||||
-rw-r--r-- | backends/ps2/Gs2dScreen.cpp | 359 | ||||
-rw-r--r-- | backends/ps2/Gs2dScreen.h | 15 | ||||
-rw-r--r-- | backends/ps2/GsDefs.h | 11 | ||||
-rw-r--r-- | backends/ps2/asyncfio.cpp | 50 | ||||
-rw-r--r-- | backends/ps2/asyncfio.h | 5 | ||||
-rw-r--r-- | backends/ps2/fileio.cpp | 655 | ||||
-rw-r--r-- | backends/ps2/fileio.h | 47 | ||||
-rw-r--r-- | backends/ps2/libkbd.cpp | 191 | ||||
-rw-r--r-- | backends/ps2/ps2input.cpp | 3 | ||||
-rw-r--r-- | backends/ps2/ps2pad.cpp | 15 | ||||
-rw-r--r-- | backends/ps2/ps2pad.h | 2 | ||||
-rw-r--r-- | backends/ps2/savefile.cpp | 540 | ||||
-rw-r--r-- | backends/ps2/savefile.h | 34 | ||||
-rw-r--r-- | backends/ps2/sjpcm.h | 56 | ||||
-rw-r--r-- | backends/ps2/smushio.cpp | 376 | ||||
-rw-r--r-- | backends/ps2/sysdefs.h | 6 | ||||
-rw-r--r-- | backends/ps2/systemps2.cpp | 179 | ||||
-rw-r--r-- | backends/ps2/systemps2.h | 3 |
20 files changed, 1453 insertions, 1134 deletions
diff --git a/backends/ps2/DmaPipe.cpp b/backends/ps2/DmaPipe.cpp index c59b6f5020..383ffe9102 100644 --- a/backends/ps2/DmaPipe.cpp +++ b/backends/ps2/DmaPipe.cpp @@ -128,15 +128,15 @@ void DmaPipe::setTex(uint32 tex, uint32 texBufWidth, uint8 texPowW, uint8 texPow _pipes[_curPipe]->setReg( GPR_CLAMP_1, 0); } -void DmaPipe::textureRect(uint16 x1, uint16 y1, uint16 u1, uint16 v1, uint16 x2, uint16 y2, uint16 u2, uint16 v2, uint16 z, uint32 colour) { +void DmaPipe::textureRect(const GsVertex *p1, const GsVertex *p2, const TexVertex *t1, const TexVertex *t2) { checkSpace(4); _pipes[_curPipe]->setGifRegListTag( 6, 0xffffffffff535310); _pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_SPRITE, 0, 1, 0, 1, 0, 1, 0, 0), - GS_SET_COLQ(colour)); - _pipes[_curPipe]->setListReg( GS_SET_UV(u1, v1), - GS_SET_XYZ(x1, y1, z)); - _pipes[_curPipe]->setListReg( GS_SET_UV(u2, v2), - GS_SET_XYZ(x2, y2, z)); + GS_SET_COLQ(GS_RGBA(0x80, 0x80, 0x80, 0x80))); + _pipes[_curPipe]->setListReg( GS_SET_UV(t1->u, t1->v), + GS_SET_XYZ(p1->x, p1->y, p1->z)); + _pipes[_curPipe]->setListReg( GS_SET_UV(t2->u, t2->v), + GS_SET_XYZ(p2->x, p2->y, p2->z)); } void DmaPipe::textureRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, const TexVertex *t1, const TexVertex *t2, const TexVertex *t3, const TexVertex *t4, uint32 rgba) { @@ -155,18 +155,6 @@ void DmaPipe::textureRect(const GsVertex *p1, const GsVertex *p2, const GsVertex GS_SET_XYZ(p4->x, p4->y, p4->z)); } -/*void DmaPipe::flatRect(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint16 x3, uint16 y3, uint16 x4, uint16 y4, uint16 z, uint32 rgba) { - checkSpace(4); - _pipes[_curPipe]->setGifRegListTag( 6, 0xffffffffff555510); - //_pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_TRIANGLESTRIP, 0, 0, 0, 1, 0, 0, 0, 0), - _pipes[_curPipe]->setListReg( GS_SET_PRIM(PR_TRIANGLESTRIP, 0, 0, 0, 0, 0, 0, 0, 0), - GS_SET_COLQ(rgba)); - _pipes[_curPipe]->setListReg( GS_SET_XYZ(x2, y2, z), - GS_SET_XYZ(x1, y1, z)); - _pipes[_curPipe]->setListReg( GS_SET_XYZ(x3, y3, z), - GS_SET_XYZ(x4, y4, z)); -}*/ - void DmaPipe::flatRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, uint32 rgba) { checkSpace(4); _pipes[_curPipe]->setGifRegListTag( 6, 0xffffffffff555510); @@ -205,10 +193,7 @@ void DmaPipe::setConfig(uint8 prModeCont, uint8 dither, uint8 colClamp) { // set some defaults // alpha blending formula: (A-B) * C + D - // set: A = source pixel, b = 0, C = source alpha, D = destination pixel, fix = don't care - //_pipes[_curPipe]->setReg(GPR_ALPHA_1, GS_SET_ALPHA(SOURCE_COLOR, ZERO_COLOR, SOURCE_ALPHA, DEST_COLOR, 0)); - // set: A = source pixel, b = dest pixel, C = source alpha, D = destination pixel, fix = don't care - //_pipes[_curPipe]->setReg( GPR_ALPHA_1, GS_SET_ALPHA(SOURCE_COLOR, DEST_COLOR, SOURCE_ALPHA, DEST_COLOR, 0x7F)); + // set: A = dest pixel, b = 0, C = source alpha, D = source pixel, fix = don't care _pipes[_curPipe]->setReg(GPR_ALPHA_1, GS_SET_ALPHA(DEST_COLOR, ZERO_COLOR, SOURCE_ALPHA, SOURCE_COLOR, 0)); _pipes[_curPipe]->setReg( GPR_PRIM, 0); @@ -233,6 +218,14 @@ void DmaPipe::setDrawBuffer(uint64 base, uint64 width, uint8 pixelFmt, uint64 ma _pipes[_curPipe]->setReg( GPR_FRAME_1, GS_SET_FRAME(base / 8192, width / 64, pixelFmt, mask)); } +void DmaPipe::setFinishEvent(void) { + checkSpace(3); + // make GS generate a FINISH interrupt when it's done. + _pipes[_curPipe]->setGifLoopTag(2); + _pipes[_curPipe]->setReg( GPR_FINISH, 1); + _pipes[_curPipe]->setReg( GPR_SIGNAL, 1); +} + void DmaPipe::checkSpace(uint32 needed) { if (_pipes[_curPipe]->spaceLeft() < (needed << 1)) flush(); diff --git a/backends/ps2/DmaPipe.h b/backends/ps2/DmaPipe.h index e032182eae..eebd0f75fa 100644 --- a/backends/ps2/DmaPipe.h +++ b/backends/ps2/DmaPipe.h @@ -43,8 +43,8 @@ public: void uploadTex(uint32 dest, uint16 bufWidth, uint16 destOfsX, uint16 destOfsY, uint8 pixelFmt, const void *src, uint16 width, uint16 height); void setTex(uint32 tex, uint32 texBufWidth, uint8 texPowW, uint8 texPowH, uint8 texPixFmt, uint32 clut, uint8 csm, uint32 clutBufWidth, uint32 clutPixFmt); void setDrawBuffer(uint64 base, uint64 width, uint8 pixelFmt, uint64 mask); - void textureRect(uint16 x1, uint16 y1, uint16 u1, uint16 v1, uint16 x2, uint16 y2, uint16 u2, uint16 v2, uint16 z, uint32 colour); void textureRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, const TexVertex *t1, const TexVertex *t2, const TexVertex *t3, const TexVertex *t4, uint32 rgba); + void textureRect(const GsVertex *p1, const GsVertex *p2, const TexVertex *t1, const TexVertex *t2); void flatRect(const GsVertex *p1, const GsVertex *p2, const GsVertex *p3, const GsVertex *p4, uint32 rgba); void flatRect(const GsVertex *p1, const GsVertex *p2, uint32 rgba); @@ -52,6 +52,7 @@ public: void setConfig(uint8 prModeCont, uint8 dither, uint8 colClamp); void setScissorRect(uint64 x1, uint64 y1, uint64 x2, uint64 y2); void setAlphaBlend(AlphaBlendColor a, AlphaBlendColor b, AlphaBlendAlpha c, AlphaBlendColor d, uint8 fix); + void setFinishEvent(void); void flush(void); void waitForDma(void); private: diff --git a/backends/ps2/Gs2dScreen.cpp b/backends/ps2/Gs2dScreen.cpp index c2e547ff2e..274367847e 100644 --- a/backends/ps2/Gs2dScreen.cpp +++ b/backends/ps2/Gs2dScreen.cpp @@ -25,10 +25,9 @@ #include <string.h> #include <assert.h> #include <fileio.h> -#include <math.h> // for sqrt() +#include <math.h> #include "DmaPipe.h" #include "GsDefs.h" -#include <sio.h> enum Buffers { SCREEN = 0, @@ -37,7 +36,7 @@ enum Buffers { }; #define DEFAULT_PAL_X 175 -#define DEFAULT_PAL_Y 40 +#define DEFAULT_PAL_Y 60 #define DEFAULT_NTSC_X 165 #define DEFAULT_NTSC_Y 45 #define ORG_X 256 @@ -47,52 +46,72 @@ enum Buffers { #define TEX_POW 10 #define SCALE(x) ((x) << 4) -#define COORD_XY(x, y) SCALE((x) + ORG_X), SCALE((y) + ORG_Y) -#define COORD_UV(u, v) SCALE(u), SCALE(v) - -/*#define COORD_X1(x) SCALE((x) + ORG_X + GS_RECT_OFFSET) -#define COORD_Y1(y) SCALE((y) + ORG_Y + GS_RECT_OFFSET) -#define COORD_X2(x) SCALE((x) + ORG_X - GS_RECT_OFFSET) -#define COORD_Y2(y) SCALE((y) + ORG_Y - GS_RECT_OFFSET) -#define COORD_XY1(x, y) COORD_X1(x), COORD_Y1(y) -#define COORD_XY2(x, y) COORD_X2(x), COORD_Y2(y)*/ #define M_SIZE 128 #define M_POW 7 #define PI 3.1415926535897932384626433832795 -static volatile uint32 g_VblankCmd, g_DmacCmd; +static volatile uint32 g_VblankCmd = 0, g_DmacCmd = 0; +static int g_VblankSema, g_DmacSema, g_AnimSema; +static bool g_RunAnim = false; +static GsVertex kFullScreen[2]; +static TexVertex kMouseTex[2] = { + { SCALE(1), SCALE(1) }, + { SCALE(M_SIZE), SCALE(M_SIZE) } +}; + +void sioprintf(const char *zFormat, ...); -int32 vblankHandler(int32 cause) { +int vblankStartHandler(int cause) { // start of VBlank period if (g_VblankCmd) { // is there a new image waiting? GS_DISPFB1 = g_VblankCmd; // show it. g_VblankCmd = 0; + iSignalSema(g_VblankSema); } return 0; } -int32 dmacHandler(int32 channel) { +int dmacHandler(int channel) { if (g_DmacCmd && (channel == 2)) { // GS DMA transfer finished, g_VblankCmd = g_DmacCmd; // we want to show the image g_DmacCmd = 0; // when the next vblank occurs + iSignalSema(g_DmacSema); } return 0; } +int vblankEndHandler(int cause) { + if (g_RunAnim) + iSignalSema(g_AnimSema); + return 0; +} + void createAnimThread(Gs2dScreen *screen); Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { - g_DmacCmd = g_VblankCmd = 0; - AddIntcHandler(INT_VBLANK_START, vblankHandler, 0); - AddDmacHandler(2, dmacHandler, 0); // 2 = 2nd dma channel = EE <-> GS + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + g_VblankSema = CreateSema(&newSema); + g_DmacSema = CreateSema(&newSema); + _screenSema = CreateSema(&newSema); + newSema.init_count = 0; + newSema.max_count = 255; + g_AnimSema = CreateSema(&newSema); + assert((g_VblankSema >= 0) && (g_DmacSema >= 0) && (_screenSema >= 0) && (g_AnimSema >= 0)); + + AddIntcHandler(INT_VBLANK_START, vblankStartHandler, 0); + AddIntcHandler(INT_VBLANK_END, vblankEndHandler, 0); + AddDmacHandler(2, dmacHandler, 0); _dmaPipe = new DmaPipe(0x2000); EnableIntc(INT_VBLANK_START); - EnableDmac(2); + EnableIntc(INT_VBLANK_END); + EnableDmac(2); _width = width; _height = height; @@ -103,8 +122,7 @@ Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { _clut = (uint32*)memalign(64, 256 * 4); memset(_screenBuf, 0, _width * _height); - for (uint32 cnt = 0; cnt < 256; cnt++) - _clut[cnt] = GS_RGBA(0, 0, 0, 0x80); + memset(_clut, 0, 256 * sizeof(uint32)); clearOverlay(); if (tvMode == TV_DONT_CARE) { @@ -117,9 +135,20 @@ Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { printf("Setting up %s mode\n", (_videoMode == TV_PAL) ? "PAL" : "NTSC"); - // set screen size, 640x576 for pal, 640x448 for ntsc + // set screen size, 640x544 for pal, 640x448 for ntsc _tvWidth = 640; - _tvHeight = ((_videoMode == TV_PAL) ? 576 : 448); + _tvHeight = ((_videoMode == TV_PAL) ? 544 : 448); + kFullScreen[0].z = kFullScreen[1].z = 0; + kFullScreen[0].x = ORIGIN_X; + kFullScreen[0].y = ORIGIN_Y; + kFullScreen[1].x = SCALE(_tvWidth) + ORIGIN_X; + kFullScreen[1].y = SCALE(_tvHeight) + ORIGIN_Y; + _blitCoords[0] = kFullScreen[0]; + _blitCoords[1] = kFullScreen[1]; + _texCoords[0].u = SCALE(1); + _texCoords[0].v = SCALE(1); + _texCoords[1].u = SCALE(_width); + _texCoords[1].v = SCALE(_height); uint32 tvFrameSize = _tvWidth * _tvHeight * 4; // 32 bits per pixel @@ -142,10 +171,11 @@ Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { _shakePos = 0; // setup hardware now. - GS_CSR = GS_SET_CSR(0, 0, 0, 0, 0, 1, 0); + GS_CSR = CSR_RESET; // Reset GS asm ("sync.p"); + GS_CSR = 0; - GsPutIMR(0xFF00); + GsPutIMR(0x7F00); uint16 dispPosX, dispPosY; @@ -171,25 +201,13 @@ Gs2dScreen::Gs2dScreen(uint16 width, uint16 height, TVMode tvMode) { _dmaPipe->setConfig(1, 0, 1); _dmaPipe->setScissorRect(0, 0, _tvWidth - 1, _tvHeight - 1); _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); + _dmaPipe->flush(); _clutChanged = _screenChanged = _overlayChanged = true; + updateScreen(); createAnimTextures(); - - ee_sema_t newSema; - newSema.init_count = 1; - newSema.max_count = 1; - _screenSema = CreateSema(&newSema); - - newSema.init_count = 0; - _timerSema = CreateSema(&newSema); - - if ((_screenSema < 0) || (_timerSema < 0)) { - printf("Can't create semaphores.\n"); - SleepThread(); - } - createAnimThread(this); } @@ -214,6 +232,7 @@ void Gs2dScreen::createAnimTextures(void) { _dmaPipe->waitForDma(); } _dmaPipe->uploadTex(_clutPtrs[TEXT], 64, 0, 0, GS_PSMCT32, _binaryClut, 8, 2); + _dmaPipe->flush(); free(buf); } @@ -221,33 +240,47 @@ void Gs2dScreen::newScreenSize(uint16 width, uint16 height) { if ((width == _width) && (height == _height)) return; - printf("New screen size %d/%d\n", width, height); + WaitSema(g_DmacSema); + WaitSema(g_VblankSema); + _dmaPipe->flush(); _screenChanged = _overlayChanged = false; _width = width; _height = height; _pitch = (width + 127) & ~127; - waitForImage(); // if there's a frame waiting to be shown, wait for vblank handler - // now malloc new buffers + // malloc new buffers free(_screenBuf); free(_overlayBuf); _screenBuf = (uint8*)memalign(64, _width * _height); - memset(_screenBuf, 0, _width * height); _overlayBuf = (uint16*)memalign(64, _width * _height * 2); + memset(_screenBuf, 0, _width * height); memset(_overlayBuf, 0, _width * height * 2); - _screenChanged = _overlayChanged = true; + memset(_clut, 0, 256 * sizeof(uint32)); + // clear video ram + _dmaPipe->uploadTex(_clutPtrs[MOUSE], 64, 0, 0, GS_PSMCT32, _clut, 16, 16); + _dmaPipe->uploadTex(_clutPtrs[SCREEN], 64, 0, 0, GS_PSMCT32, _clut, 16, 16); + _dmaPipe->uploadTex(_texPtrs[SCREEN], _width, 0, 0, GS_PSMCT16, _overlayBuf, _width, _height); + _dmaPipe->flush(); + _dmaPipe->waitForDma(); + + _clutChanged = _screenChanged = _overlayChanged = false; + + _texCoords[1].u = SCALE(_width); + _texCoords[1].v = SCALE(_height); _mouseScaleX = (_tvWidth << 8) / _width; _mouseScaleY = (_tvHeight << 8) / _height; setMouseXy(_width / 2, _height / 2); - printf("done\n"); + + SignalSema(g_VblankSema); + SignalSema(g_DmacSema); } void Gs2dScreen::copyScreenRect(const uint8 *buf, uint16 pitch, uint16 x, uint16 y, uint16 w, uint16 h) { - waitForDma(); - assert((x + w <= _width) && (y + h <= _height)); + + WaitSema(g_DmacSema); uint8 *dest = _screenBuf + y * _width + x; for (uint16 cnt = 0; cnt < h; cnt++) { memcpy(dest, buf, w); @@ -255,25 +288,23 @@ void Gs2dScreen::copyScreenRect(const uint8 *buf, uint16 pitch, uint16 x, uint16 dest += _width; } _screenChanged = true; + SignalSema(g_DmacSema); } void Gs2dScreen::setPalette(const uint32 *pal, uint8 start, uint16 num) { - waitForDma(); - assert(start + num <= 256); + + WaitSema(g_DmacSema); for (uint16 cnt = 0; cnt < num; cnt++) { uint16 dest = start + cnt; - dest = (dest & 0x7) | ((dest & 0x8) << 1) | ((dest & 0x10) >> 1) | (dest & 0xE0); // rearrange like the GS expects it + dest = (dest & 0xE7) | ((dest & 0x8) << 1) | ((dest & 0x10) >> 1); // rearrange like the GS expects it _clut[dest] = pal[cnt] & 0xFFFFFF; } _clutChanged = true; + SignalSema(g_DmacSema); } void Gs2dScreen::updateScreen(void) { - /* we can't draw more than 50 images on PAL and 60 on NTSC, wait until the other buffer is shown. - especcially necessary for BS2 which does hundreds of updateScreen()s per second */ - waitForImage(); - WaitSema(_screenSema); if (_clutChanged) { @@ -288,22 +319,7 @@ void Gs2dScreen::updateScreen(void) { _dmaPipe->uploadTex(_clutPtrs[SCREEN], 64, 0, 0, GS_PSMCT32, _clut, 16, 16); } - drawScreen(); - - g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24); // put it here for dmac/vblank handler - _dmaPipe->flush(); - _curDrawBuf ^= 1; - _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); - SignalSema(_screenSema); -} - -void Gs2dScreen::drawScreen(void) { - static GsVertex fullScreen[2] = { - { COORD_XY(0, 0), SCALE(0) }, - { COORD_XY(_tvWidth, _tvHeight), SCALE(0) } - }; - - _dmaPipe->flatRect(fullScreen + 0, fullScreen + 1, GS_RGBA(0, 0, 0, 0)); // clear screen + _dmaPipe->flatRect(kFullScreen + 0, kFullScreen + 1, GS_RGBA(0, 0, 0, 0)); // clear screen if (_showOverlay) { if (_overlayChanged) { @@ -311,27 +327,36 @@ void Gs2dScreen::drawScreen(void) { _overlayChanged = false; } _dmaPipe->setTex(_texPtrs[SCREEN], _width, TEX_POW, TEX_POW, GS_PSMCT16, 0, 0, 0, 0); - _dmaPipe->textureRect(COORD_XY(0, 0), COORD_UV(1, 1), - COORD_XY(_tvWidth, _tvHeight), COORD_UV(_width, _height), 0, GS_RGBA(0x80, 0x80, 0x80, 0x80)); + _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, _texCoords + 0, _texCoords + 1); } else { if (_screenChanged) { _dmaPipe->uploadTex(_texPtrs[SCREEN], _pitch, 0, 0, GS_PSMT8, _screenBuf, _width, _height); _screenChanged = false; } _dmaPipe->setTex(_texPtrs[SCREEN], _pitch, TEX_POW, TEX_POW, GS_PSMT8, _clutPtrs[SCREEN], 0, 64, GS_PSMCT32); - _dmaPipe->textureRect(COORD_XY(0, -_shakePos), COORD_UV(1, 1), - COORD_XY(_tvWidth, _tvHeight - _shakePos), COORD_UV(_width, _height), 0, GS_RGBA(0x80, 0x80, 0x80, 0x80)); + _dmaPipe->textureRect(_blitCoords + 0, _blitCoords + 1, _texCoords + 0, _texCoords + 1); } if (_showMouse) { + GsVertex mouseCoords[2]; + mouseCoords[0].x = (((_mouseX - _hotSpotX) * _mouseScaleX + 8) >> 4) + ORIGIN_X; + mouseCoords[0].y = (((_mouseY - _hotSpotY) * _mouseScaleY + 8) >> 4) + ORIGIN_Y; + mouseCoords[1].x = mouseCoords[0].x + (((M_SIZE * _mouseScaleX) + 8) >> 4); + mouseCoords[1].y = mouseCoords[0].y + (((M_SIZE * _mouseScaleY) + 8) >> 4); + mouseCoords[0].z = mouseCoords[1].z = 0; + _dmaPipe->setTex(_texPtrs[MOUSE], M_SIZE, M_POW, M_POW, GS_PSMT8H, _clutPtrs[MOUSE], 0, 64, GS_PSMCT32); - uint16 mpX1 = (((_mouseX - _hotSpotX) * _mouseScaleX + 128) >> 4) + ORIGIN_X; - uint16 mpY1 = (((_mouseY - _hotSpotY) * _mouseScaleY + 128) >> 4) + ORIGIN_Y; - uint16 mpX2 = mpX1 + ((M_SIZE * _mouseScaleX + 128) >> 4); - uint16 mpY2 = mpY1 + ((M_SIZE * _mouseScaleY + 128) >> 4); - _dmaPipe->textureRect(mpX1, mpY1, COORD_UV(0, 0), - mpX2, mpY2, COORD_UV(M_SIZE - 1, M_SIZE - 1), 0, GS_RGBA(0x80, 0x80, 0x80, 0x80)); + _dmaPipe->textureRect(mouseCoords + 0, mouseCoords + 1, kMouseTex + 0, kMouseTex + 1); } + + WaitSema(g_DmacSema); // wait for dma transfer, if there's one running + WaitSema(g_VblankSema); // wait if there's already an image waiting for vblank + + g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24); // put it here for dmac/vblank handler + _dmaPipe->flush(); + _curDrawBuf ^= 1; + _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); + SignalSema(_screenSema); } void Gs2dScreen::showOverlay(void) { @@ -346,11 +371,12 @@ void Gs2dScreen::hideOverlay(void) { void Gs2dScreen::setShakePos(int shake) { _shakePos = (shake * _mouseScaleY) >> 8; + _blitCoords[0].y = SCALE(_shakePos) + ORIGIN_Y; + _blitCoords[1].y = SCALE(_tvHeight + _shakePos) + ORIGIN_Y; } void Gs2dScreen::copyOverlayRect(const uint16 *buf, uint16 pitch, uint16 x, uint16 y, uint16 w, uint16 h) { - waitForDma(); - + WaitSema(g_DmacSema); _overlayChanged = true; uint16 *dest = _overlayBuf + y * _width + x; for (uint32 cnt = 0; cnt < h; cnt++) { @@ -358,21 +384,22 @@ void Gs2dScreen::copyOverlayRect(const uint16 *buf, uint16 pitch, uint16 x, uint dest += _width; buf += pitch; } + SignalSema(g_DmacSema); } void Gs2dScreen::clearOverlay(void) { - waitForDma(); - + WaitSema(g_DmacSema); _overlayChanged = true; // first convert our clut to 16 bit RGBA for the overlay... uint16 palette[256]; for (uint32 cnt = 0; cnt < 256; cnt++) { - uint32 rgba = _clut[(cnt & 0x7) | ((cnt & 0x8) << 1) | ((cnt & 0x10) >> 1) | (cnt & 0xE0)]; + uint32 rgba = _clut[(cnt & 0xE7) | ((cnt & 0x8) << 1) | ((cnt & 0x10) >> 1)]; palette[cnt] = ((rgba >> 3) & 0x1F) | (((rgba >> 11) & 0x1F) << 5) | (((rgba >> 19) & 0x1F) << 10); } // now copy the current screen over for (uint32 cnt = 0; cnt < _width * _height; cnt++) _overlayBuf[cnt] = palette[_screenBuf[cnt]]; + SignalSema(g_DmacSema); } void Gs2dScreen::grabOverlay(uint16 *buf, uint16 pitch) { @@ -398,30 +425,12 @@ void Gs2dScreen::setMouseOverlay(const uint8 *buf, uint16 width, uint16 height, for (int cnt = 0; cnt < height; cnt++) memcpy(bufCopy + cnt * M_SIZE, buf + cnt * width, width); - _dmaPipe->uploadTex( _texPtrs[MOUSE], M_SIZE, 0, 0, GS_PSMT8H, bufCopy, M_SIZE, M_SIZE); + _dmaPipe->uploadTex( _texPtrs[MOUSE], M_SIZE, 0, 0, GS_PSMT8H, bufCopy, M_SIZE, M_SIZE); _dmaPipe->flush(); _dmaPipe->waitForDma(); // make sure all data has been transferred when we free bufCopy free(bufCopy); } -void Gs2dScreen::waitForDma(void) { - // wait until dma transfer finished - while (g_DmacCmd) - ; -} - -void Gs2dScreen::waitForImage(void) { - /* if there's an image waiting to be shown on next vblank, wait for it. - however, first we must wait for the dma transfer (if running) as it will - result in a new image */ - waitForDma(); - while (g_VblankCmd) - ; - /* both waitForImage and waitForDma should only get called by the main thread, - so they may be implemented as busy waits, as both the timer- and sound-thread have - a higher priority than this one. There's no thread we could switch to anyways... */ -} - void Gs2dScreen::showMouse(bool show) { _showMouse = show; } @@ -435,94 +444,103 @@ uint8 Gs2dScreen::tvMode(void) { return _videoMode; } +void Gs2dScreen::wantAnim(bool runIt) { + g_RunAnim = runIt; +} + #define LINE_SPACE 20 #define SCRL_TIME 8 #define V 1000 #define Z_TRANSL 65 -void Gs2dScreen::wantAnim(bool runIt) { - _runAnim = runIt; -} - void Gs2dScreen::animThread(void) { // animate zeros and ones while game accesses memory card, etc. - _runAnim = false; + g_RunAnim = false; float yPos = 0.0; uint8 texSta = 0; float scrlSpeed = (_videoMode == TV_PAL) ? (_tvHeight / (SCRL_TIME * 50.0)) : (_tvHeight / (SCRL_TIME * 60.0)); uint8 texMax = (_tvHeight / LINE_SPACE) + (ORG_Y / LINE_SPACE); TexVertex texNodes[4] = { - { COORD_UV( 0, 0) }, { COORD_UV( 0, 14) }, - { COORD_UV(128, 0) }, { COORD_UV(128, 14) } + { SCALE(1), SCALE(1) }, { SCALE(1), SCALE(14) }, + { SCALE(128), SCALE(1) }, { SCALE(128), SCALE(14) } }; float angleStep = ((2 * PI) / _tvHeight); while (1) { - WaitSema(_timerSema); - if (_runAnim && !g_DmacCmd && !g_VblankCmd) { - if (PollSema(_screenSema) > 0) { - drawScreen(); // draw the last screen the engine did again - - _dmaPipe->setAlphaBlend(SOURCE_COLOR, ZERO_COLOR, SOURCE_ALPHA, DEST_COLOR, 0); - yPos -= scrlSpeed; - if (yPos <= -LINE_SPACE) { - yPos += LINE_SPACE; - texSta++; - } + do { + WaitSema(g_AnimSema); + } while (!g_RunAnim); + + if (PollSema(_screenSema) > 0) { // make sure no thread is currently drawing + WaitSema(g_DmacSema); // dma transfers have to be finished + WaitSema(g_VblankSema); // wait for image, if there is one... + + // redraw the engine's last frame + _dmaPipe->flatRect(kFullScreen + 0, kFullScreen + 1, GS_RGBA(0, 0, 0, 0)); // clear screen + + if (_showOverlay) { + _dmaPipe->setTex(_texPtrs[SCREEN], _width, TEX_POW, TEX_POW, GS_PSMCT16, 0, 0, 0, 0); + _dmaPipe->textureRect(kFullScreen + 0, kFullScreen + 1, _texCoords + 0, _texCoords + 1); + } else { + _dmaPipe->setTex(_texPtrs[SCREEN], _pitch, TEX_POW, TEX_POW, GS_PSMT8, _clutPtrs[SCREEN], 0, 64, GS_PSMCT32); + _dmaPipe->textureRect(_blitCoords + 0, _blitCoords + 1, _texCoords + 0, _texCoords + 1); + } - float drawY = yPos; - - for (int i = 0; i < texMax; i++) { - uint8 texIdx = (texSta + i) & 0xF; - - float x[4] = { -64.0, -64.0, 64.0, 64.0 }; - float y[4]; - y[0] = y[2] = drawY - _tvHeight / 2 - LINE_SPACE / 2; - y[1] = y[3] = y[0] + LINE_SPACE; - float z[4] = { 0.0, 0.0, 0.0, 0.0 }; - GsVertex nodes[4]; - - float angle = PI / 2 + angleStep * drawY; - float rotSin = sinf(angle); - float rotCos = cosf(angle); - for (int coord = 0; coord < 4; coord++) { - z[coord] = rotCos * x[coord]; - x[coord] = rotSin * x[coord]; - - nodes[coord].z = 0; - nodes[coord].x = (uint16)(((V * x[coord]) / (z[coord] + V + Z_TRANSL)) * 16); - nodes[coord].y = (uint16)(((V * y[coord]) / (z[coord] + V + Z_TRANSL)) * 16); - nodes[coord].x += SCALE(_tvWidth - 80 + ORG_X); - nodes[coord].y += SCALE(_tvHeight / 2 + ORG_Y); - } - - uint32 texPtr = _texPtrs[TEXT] + 128 * 16 * 4 * (texIdx >> 1); - if (texIdx & 1) - _dmaPipe->setTex(_texPtrs[TEXT], 128, 7, 4, GS_PSMT4HL, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); - else - _dmaPipe->setTex(_texPtrs[TEXT], 128, 7, 4, GS_PSMT4HH, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); - - _dmaPipe->textureRect(nodes + 0, nodes + 1, nodes + 2, nodes + 3, - texNodes + 0, texNodes + 1, texNodes + 2, texNodes + 3, GS_RGBA(0x80, 0x80, 0x80, 0x80)); - - drawY += LINE_SPACE; + _dmaPipe->setAlphaBlend(SOURCE_COLOR, ZERO_COLOR, SOURCE_ALPHA, DEST_COLOR, 0); + yPos -= scrlSpeed; + if (yPos <= -LINE_SPACE) { + yPos += LINE_SPACE; + texSta++; + } + + float drawY = yPos; + + for (int i = 0; i < texMax; i++) { + uint8 texIdx = (texSta + i) & 0xF; + + float x[4] = { -64.0, -64.0, 64.0, 64.0 }; + float y[4]; + y[0] = y[2] = drawY - _tvHeight / 2 - LINE_SPACE / 2; + y[1] = y[3] = y[0] + LINE_SPACE; + float z[4]; + GsVertex nodes[4]; + + float angle = PI / 2 + angleStep * drawY; + float rotSin = sinf(angle); + float rotCos = cosf(angle); + for (int coord = 0; coord < 4; coord++) { + z[coord] = rotCos * x[coord]; + x[coord] = rotSin * x[coord]; + + nodes[coord].z = 0; + nodes[coord].x = (uint16)(((V * x[coord]) / (z[coord] + V + Z_TRANSL)) * 16); + nodes[coord].y = (uint16)(((V * y[coord]) / (z[coord] + V + Z_TRANSL)) * 16); + nodes[coord].x += SCALE(_tvWidth - 80 + ORG_X); + nodes[coord].y += SCALE(_tvHeight / 2 + ORG_Y); } - g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24); // put it here for dmac/vblank handler - _dmaPipe->flush(); - _curDrawBuf ^= 1; - _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); - _dmaPipe->setAlphaBlend(DEST_COLOR, ZERO_COLOR, SOURCE_ALPHA, SOURCE_COLOR, 0); - SignalSema(_screenSema); + + uint32 texPtr = _texPtrs[TEXT] + 128 * 16 * 4 * (texIdx >> 1); + if (texIdx & 1) + _dmaPipe->setTex(_texPtrs[TEXT], 128, 7, 4, GS_PSMT4HL, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + else + _dmaPipe->setTex(_texPtrs[TEXT], 128, 7, 4, GS_PSMT4HH, _clutPtrs[TEXT], 0, 64, GS_PSMCT32); + + _dmaPipe->textureRect(nodes + 0, nodes + 1, nodes + 2, nodes + 3, + texNodes + 0, texNodes + 1, texNodes + 2, texNodes + 3, GS_RGBA(0x80, 0x80, 0x80, 0x80)); + + drawY += LINE_SPACE; } + g_DmacCmd = GS_SET_DISPFB(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24); // put it here for dmac/vblank handler + _dmaPipe->flush(); + _curDrawBuf ^= 1; + _dmaPipe->setDrawBuffer(_frameBufPtr[_curDrawBuf], _tvWidth, GS_PSMCT24, 0); + _dmaPipe->setAlphaBlend(DEST_COLOR, ZERO_COLOR, SOURCE_ALPHA, SOURCE_COLOR, 0); + + SignalSema(_screenSema); } } } -void Gs2dScreen::timerTick(void) { - if (_runAnim) - SignalSema(_timerSema); -} - void runAnimThread(Gs2dScreen *param) { param->animThread(); } @@ -533,11 +551,10 @@ void createAnimThread(Gs2dScreen *screen) { ee_thread_t animThread, thisThread; ReferThreadStatus(GetThreadId(), &thisThread); - animThread.initial_priority = thisThread.current_priority - 1; + animThread.initial_priority = thisThread.current_priority - 3; animThread.stack = malloc(ANIM_STACK_SIZE); animThread.stack_size = ANIM_STACK_SIZE; animThread.func = (void *)runAnimThread; - //animThread.gp_reg = _gp; for some reason _gp is always NULL asm("move %0, $gp\n": "=r"(animThread.gp_reg)); int tid = CreateThread(&animThread); diff --git a/backends/ps2/Gs2dScreen.h b/backends/ps2/Gs2dScreen.h index 95ae2b522c..7f011b5a8a 100644 --- a/backends/ps2/Gs2dScreen.h +++ b/backends/ps2/Gs2dScreen.h @@ -23,9 +23,7 @@ #define __GS2DSCREEN_H__ #include "sysdefs.h" - -#define SUPPORT_STUPID_OVERLAYS - +#include "backends/ps2/DmaPipe.h" enum TVMode { TV_DONT_CARE = 0, TV_PAL, @@ -37,7 +35,7 @@ enum GsInterlace { GS_INTERLACED }; -class DmaPipe; +//class DmaPipe; class Gs2dScreen { public: @@ -62,17 +60,15 @@ public: void setShakePos(int shake); void animThread(void); - void timerTick(void); void wantAnim(bool runIt); private: void createAnimTextures(void); - void drawScreen(void); - static inline void waitForDma(void); - static inline void waitForImage(void); DmaPipe *_dmaPipe; uint8 _videoMode; uint16 _tvWidth, _tvHeight; + GsVertex _blitCoords[2]; + TexVertex _texCoords[2]; uint8 _curDrawBuf; uint32 _frameBufPtr[2]; // @@ -91,8 +87,7 @@ private: uint8 *_screenBuf; uint32 *_clut; - bool _runAnim; - int _timerSema, _screenSema; + int _screenSema; static const uint32 _binaryClut[16]; static const uint8 _binaryData[4 * 14 * 2]; static const uint16 _binaryPattern[16]; diff --git a/backends/ps2/GsDefs.h b/backends/ps2/GsDefs.h index c744eeaa2b..e3966b3a3b 100644 --- a/backends/ps2/GsDefs.h +++ b/backends/ps2/GsDefs.h @@ -34,9 +34,14 @@ #define GS_DISPLAY1 *((volatile uint64*)0x12000080) #define GS_BGCOLOUR *((volatile uint64*)0x120000E0) -#define GS_SET_CSR(signal, finish, hsint, vsint, flush, reset, field) \ - ((signal) | ((finish) << 1) | ((hsint) << 2) | ((vsint) << 3) | \ - ((flush) << 8) | ((reset) << 9) | ((field) << 13)) +enum GS_CSR_FIELDS { + CSR_SIGNAL = 1 << 0, + CSR_FINISH = 1 << 1, + CSR_HSYNC = 1 << 2, + CSR_VSYNC = 1 << 3, + CSR_FLUSH = 1 << 8, + CSR_RESET = 1 << 9 +}; #define GS_SET_PMODE(readC1, readC2, alphaSel, alphaOut, alphaBlend, alphaFixed) \ ((readC1) | ((readC2) << 1) | ((alphaSel) << 5) | ((alphaOut) << 6) | ((alphaBlend) << 7) | ((alphaFixed) << 8)) diff --git a/backends/ps2/asyncfio.cpp b/backends/ps2/asyncfio.cpp index 605f6c9aa5..9d6c27b3c3 100644 --- a/backends/ps2/asyncfio.cpp +++ b/backends/ps2/asyncfio.cpp @@ -25,12 +25,15 @@ #include <fileio.h> #include <assert.h> #include <string.h> +#include <fileXio_rpc.h> + +#define DEFAULT_MODE (FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IROTH | FIO_S_IWOTH) extern void sioprintf(const char *zFormat, ...); AsyncFio::AsyncFio(void) { _runningOp = NULL; - memset(_ioSlots, 0, MAX_HANDLES * sizeof(int)); + memset((int *)_ioSlots, 0, MAX_HANDLES * sizeof(int)); ee_sema_t newSema; newSema.init_count = 1; newSema.max_count = 1; @@ -45,9 +48,9 @@ int AsyncFio::open(const char *name, int ioMode) { WaitSema(_ioSema); checkSync(); int res; - fioOpen(name, ioMode); - int fioRes = fioSync(FIO_WAIT, &res); - if (fioRes != FIO_COMPLETE) { + fileXioOpen(name, ioMode, DEFAULT_MODE); + int fioRes = fileXioWaitAsync(FXIO_WAIT, &res); + if (fioRes != FXIO_COMPLETE) { sioprintf("ERROR: fioOpen(%s, %X):\n", name, ioMode); sioprintf(" fioSync returned %d, open res = %d\n", fioRes, res); SleepThread(); @@ -59,13 +62,20 @@ int AsyncFio::open(const char *name, int ioMode) { void AsyncFio::close(int handle) { WaitSema(_ioSema); checkSync(); - fioClose(handle); + fileXioClose(handle); + int res; + assert(fileXioWaitAsync(FXIO_WAIT, &res) == FXIO_COMPLETE); + if (res != 0) { + sioprintf("ERROR: fileXioClose failed, EC %d", res); + SleepThread(); + } + _ioSlots[handle] = 0; SignalSema(_ioSema); } void AsyncFio::checkSync(void) { if (_runningOp) { - assert(fioSync(FIO_WAIT, _runningOp) == FIO_COMPLETE); + assert(fileXioWaitAsync(FXIO_WAIT, (int *)_runningOp) == FXIO_COMPLETE); _runningOp = NULL; } } @@ -75,7 +85,7 @@ void AsyncFio::read(int fd, void *dest, unsigned int len) { checkSync(); assert(fd < MAX_HANDLES); _runningOp = _ioSlots + fd; - fioRead(fd, dest, len); + fileXioRead(fd, (unsigned char*)dest, len); SignalSema(_ioSema); } @@ -84,14 +94,26 @@ void AsyncFio::write(int fd, const void *src, unsigned int len) { checkSync(); assert(fd < MAX_HANDLES); _runningOp = _ioSlots + fd; - fioWrite(fd, (unsigned char*)src, len); + fileXioWrite(fd, (unsigned char*)src, len); SignalSema(_ioSema); } int AsyncFio::seek(int fd, int offset, int whence) { WaitSema(_ioSema); checkSync(); - int res = fioLseek(fd, offset, whence); + fileXioLseek(fd, offset, whence); + int res; + assert(fileXioWaitAsync(FXIO_WAIT, &res) == FXIO_COMPLETE); + SignalSema(_ioSema); + return res; +} + +int AsyncFio::mkdir(const char *name) { + WaitSema(_ioSema); + checkSync(); + fileXioMkdir(name, DEFAULT_MODE); + int res; + assert(fileXioWaitAsync(FXIO_WAIT, &res) == FXIO_COMPLETE); SignalSema(_ioSema); return res; } @@ -100,15 +122,17 @@ int AsyncFio::sync(int fd) { WaitSema(_ioSema); if (_runningOp == _ioSlots + fd) checkSync(); + int res = _ioSlots[fd]; + _ioSlots[fd] = 0; SignalSema(_ioSema); - return _ioSlots[fd]; + return res; } bool AsyncFio::poll(int fd) { bool retVal = false; - if (PollSema(_ioSema) > 0) { + if (PollSema(_ioSema) >= 0) { if (_runningOp == _ioSlots + fd) { - if (fioSync(FIO_NOWAIT, _runningOp) == FIO_COMPLETE) { + if (fileXioWaitAsync(FXIO_NOWAIT, (int *)_runningOp) == FXIO_COMPLETE) { _runningOp = NULL; retVal = true; } else @@ -124,7 +148,7 @@ bool AsyncFio::fioAvail(void) { bool retVal = false; if (PollSema(_ioSema) > 0) { if (_runningOp) { - if (fioSync(FIO_NOWAIT, _runningOp) == FIO_COMPLETE) { + if (fileXioWaitAsync(FXIO_NOWAIT, (int *)_runningOp) == FXIO_COMPLETE) { _runningOp = NULL; retVal = true; } else diff --git a/backends/ps2/asyncfio.h b/backends/ps2/asyncfio.h index 3518126168..765b7eb74f 100644 --- a/backends/ps2/asyncfio.h +++ b/backends/ps2/asyncfio.h @@ -30,13 +30,14 @@ public: void read(int fd, void *dest, unsigned int len); void write(int fd, const void *src, unsigned int len); int seek(int fd, int offset, int whence); + int mkdir(const char *name); int sync(int fd); bool poll(int fd); bool fioAvail(void); private: void checkSync(void); int _ioSema; - int *_runningOp; - int _ioSlots[MAX_HANDLES]; + volatile int * volatile _runningOp; + volatile int _ioSlots[MAX_HANDLES]; }; diff --git a/backends/ps2/fileio.cpp b/backends/ps2/fileio.cpp index 360666e741..f8d86712e5 100644 --- a/backends/ps2/fileio.cpp +++ b/backends/ps2/fileio.cpp @@ -26,385 +26,367 @@ #include <fileio.h> #include <assert.h> #include <string.h> -//#include <fileXio_rpc.h> #include <cdvd_rpc.h> #include "backends/ps2/asyncfio.h" #include "base/engine.h" #include "common/file.h" -#define CACHE_BUF_SIZE (2048 * 16) -#define MAX_CACHED_FILES 8 - -//#define DEFAULT_MODE (FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IROTH | FIO_S_IWOTH) +#define CACHE_SIZE (2048 * 32) +#define MAX_READ_STEP (2048 * 16) +#define MAX_CACHED_FILES 6 +#define CACHE_READ_THRESHOLD (16 * 2048) +#define CACHE_FILL_MIN (2048 * 24) extern void sioprintf(const char *zFormat, ...); AsyncFio fio; -AccessFio::AccessFio(void) { - _handle = -1; -} - -AccessFio::~AccessFio(void) { - if (_handle >= 0) - fio.close(_handle); -} - -int32 AccessFio::sync(void) { - return fio.sync(_handle); -} - -bool AccessFio::poll(void) { - return fio.poll(_handle); -} - -bool AccessFio::fioAvail(void) { - return fio.fioAvail(); -} - -bool AccessFio::open(const char *name, int mode) { - _handle = fio.open(name, mode); - return (_handle >= 0); -} - -void AccessFio::read(void *dest, uint32 size) { - fio.read(_handle, dest, size); -} - -void AccessFio::write(const void *src, uint32 size) { - fio.write(_handle, src, size); +Ps2File::Ps2File(int64 cacheId) { + _cacheId = cacheId; } -int AccessFio::seek(int32 offset, int whence) { - return fio.seek(_handle, offset, whence); +Ps2File::~Ps2File(void) { } -/*class AccessFioX : public AccessFio{ +class Ps2ReadFile : public Ps2File { public: - AccessFioX(void); - virtual ~AccessFioX(void); - virtual bool open(const char *name, int mode); - virtual int read(void *dest, uint32 size); - virtual int write(const void *src, uint32 size); - virtual int seek(int32 offset, int whence); - virtual void sync(int32 *res); -}; - -AccessFioX::AccessFioX(void) { - _handle = -1; -} - -AccessFioX::~AccessFioX(void) { - if (_handle >= 0) - fileXioClose(_handle); -} - -void AccessFioX::sync(int32 *res) { - assert(false); -} - -bool AccessFioX::open(const char *name, int mode) { - _handle = fileXioOpen(name, mode, DEFAULT_MODE); - return (_handle >= 0); -} - -int AccessFioX::read(void *dest, uint32 size) { - return fileXioRead(_handle, (unsigned char*)dest, size); -} - -int AccessFioX::write(const void *src, uint32 size) { - return fileXioWrite(_handle, (unsigned char*)src, size); -} - -int AccessFioX::seek(int32 offset, int whence) { - return fileXioLseek(_handle, offset, whence); -}*/ - -struct TocNode { - char name[64]; - TocNode *next, *sub; - bool isDir; - uint8 nameLen; -}; - -class TocManager { -public: - TocManager(void); - ~TocManager(void); - void readEntries(const char *root); - int64 fileExists(const char *name); - bool haveEntries(void); + Ps2ReadFile(int64 cacheId); + virtual ~Ps2ReadFile(void); + virtual bool open(const char *name); + virtual uint32 read(void *dest, uint32 len); + virtual uint32 write(const void *src, uint32 len); + virtual uint32 tell(void); + virtual uint32 size(void); + virtual int seek(int32 offset, int origin); + virtual bool eof(void); private: - void readDir(const char *path, TocNode **node, int level); - TocNode *_rootNode; - char _root[256]; - uint8 _rootLen; -}; + void cacheReadAhead(void); + void cacheReadSync(void); + int _fd, _sema; + uint8 *_cacheBuf; + bool _cacheOpRunning; + uint32 _filePos, _physFilePos, _cachePos; + uint32 _fileSize, _bytesInCache, _cacheOfs; -class Ps2File { -public: - Ps2File(int64 cacheId); - ~Ps2File(void); - bool open(const char *name, int ioMode); - bool isOpen(void); - uint32 read(void *dest, uint32 size); - uint32 write(const void *src, uint32 size); - uint32 tell(void); - uint32 size(void); - int seek(int32 offset, int origin); - bool eof(void); - AccessFio *giveHandle(void); - int64 _cacheId; - void setSeekReset(void); -private: - void checkCache(void); - void syncCache(void); - bool _cacheOp; - bool _seekReset; - - bool _forWriting; - AccessFio *_handle; - uint8 *_cacheBuf, *_cachePos; - uint32 _filePos; - uint32 _cacheBytesLeft; - uint32 _fSize; uint32 _readBytesBlock; }; -Ps2File::Ps2File(int64 cacheId) { - _handle = NULL; - _cachePos = _cacheBuf = (uint8*)malloc(CACHE_BUF_SIZE); - _fSize = _filePos = _cacheBytesLeft = 0; - _forWriting = false; +Ps2ReadFile::Ps2ReadFile(int64 cacheId) : Ps2File(cacheId) { + _fd = -1; + _cacheBuf = (uint8*)memalign(64, CACHE_SIZE); + + _cacheOpRunning = 0; + _filePos = _physFilePos = _cachePos = 0; + _fileSize = _bytesInCache = _cacheOfs = 0; + _cacheOpRunning = false; _readBytesBlock = 0; - _cacheOp = false; - _cacheId = cacheId; - _seekReset = false; + + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + _sema = CreateSema(&newSema); + assert(_sema >= 0); } -Ps2File::~Ps2File(void) { - if (_handle != NULL) { - syncCache(); - if (_forWriting && (_cachePos != _cacheBuf)) { - _handle->write(_cacheBuf, _cachePos - _cacheBuf); - int res = _handle->sync(); - if (res != (_cachePos - _cacheBuf)) { - // Fixme: writing operation failed and we noticed - // too late to return an error to the engine. - printf("ERROR: flushing the cache on fclose() failed!\n"); - } - } - delete _handle; - } +Ps2ReadFile::~Ps2ReadFile(void) { + if (_cacheOpRunning) + cacheReadSync(); free(_cacheBuf); + if (_fd >= 0) + fio.close(_fd); + DeleteSema(_sema); } -bool Ps2File::open(const char *name, int ioMode) { - //if (strncmp(name, "pfs0", 4) == 0) - // _handle = new AccessFioX(); - //else - _handle = new AccessFio(); - - if (_handle->open(name, ioMode)) { - if (ioMode == O_RDONLY) { - _fSize = _handle->seek(0, SEEK_END); - _handle->seek(0, SEEK_SET); - } else { - _cacheBytesLeft = CACHE_BUF_SIZE; - _forWriting = true; - } +bool Ps2ReadFile::open(const char *name) { + assert(_fd < 0); + _fd = fio.open(name, O_RDONLY); + if (_fd >= 0) { + _fileSize = fio.seek(_fd, 0, SEEK_END); + fio.seek(_fd, 0, SEEK_SET); return true; - } else { - delete _handle; - _handle = NULL; + } else return false; - } } -void Ps2File::setSeekReset(void) { - _seekReset = true; +uint32 Ps2ReadFile::tell(void) { + WaitSema(_sema); + uint32 res = _filePos; + SignalSema(_sema); + return res; +} + +uint32 Ps2ReadFile::size(void) { + WaitSema(_sema); + uint32 res = _fileSize; + SignalSema(_sema); + return res; } -bool Ps2File::isOpen(void) { - return (_handle != NULL); +bool Ps2ReadFile::eof(void) { + WaitSema(_sema); + bool res = (_filePos == _fileSize); + SignalSema(_sema); + return res; } -int Ps2File::seek(int32 offset, int origin) { - assert(!_forWriting); - syncCache(); - uint32 seekDest; +int Ps2ReadFile::seek(int32 offset, int origin) { + WaitSema(_sema); + int seekDest; + int res = -1; switch (origin) { case SEEK_SET: seekDest = offset; break; case SEEK_CUR: - if (_seekReset) - seekDest = offset; - else - seekDest = _filePos + offset; + seekDest = _filePos + offset; break; case SEEK_END: - seekDest = _fSize + offset; + seekDest = _fileSize + offset; break; default: - return -1; + seekDest = -1; + break; } - _seekReset = false; - if (seekDest <= _fSize) { - if ((seekDest >= _filePos) && (seekDest < _filePos + _cacheBytesLeft)) { - uint32 cacheOffset = (seekDest - _filePos); - _cacheBytesLeft -= cacheOffset; - _cachePos += cacheOffset; - } else { - _handle->seek(seekDest, SEEK_SET); - _cacheBytesLeft = 0; - } + if ((seekDest >= 0) && (seekDest <= _fileSize)) { _filePos = seekDest; - _readBytesBlock = 0; - return 0; - } else - return -1; + res = 0; + } + SignalSema(_sema); + return res; } -bool Ps2File::eof(void) { - if ((!_forWriting) && (_filePos == _fSize)) - return true; - else - return false; -} +void Ps2ReadFile::cacheReadAhead(void) { + if (_cacheOpRunning) { + // there's already some cache read running + if (fio.poll(_fd)) // did it finish? + cacheReadSync(); // yes. + } + if ((!_cacheOpRunning) && (_readBytesBlock >= CACHE_READ_THRESHOLD) && fio.fioAvail()) { + // the engine seems to do sequential reads and there are no other I/Os going on. read ahead. + uint32 cachePosEnd = _cachePos + _bytesInCache; + + if (_cachePos > _filePos) + return; // there was a seek in the meantime, don't cache. + if (cachePosEnd - _filePos >= CACHE_FILL_MIN) + return; // cache is full enough. + if (cachePosEnd == _fileSize) + return; // can't read beyond EOF. + + assert(cachePosEnd < _fileSize); + + if (_cachePos + _bytesInCache <= _filePos) { + _cacheOfs = _bytesInCache = 0; + _cachePos = cachePosEnd = _filePos; + assert(_filePos == _physFilePos); + } else { + uint32 cacheDiff = _filePos - _cachePos; + assert(_bytesInCache >= cacheDiff); + _bytesInCache -= cacheDiff; + _cachePos += cacheDiff; + _cacheOfs = (_cacheOfs + cacheDiff) % CACHE_SIZE; + } -void Ps2File::checkCache(void) { - if (!_forWriting) { - if (_readBytesBlock > 32768) { - if (_cacheBytesLeft <= (CACHE_BUF_SIZE / 4)) { - if (_cacheBytesLeft && (_cachePos != _cacheBuf)) { - memmove(_cacheBuf, _cachePos, _cacheBytesLeft); - } - _cachePos = _cacheBuf; - _handle->read(_cacheBuf + _cacheBytesLeft, CACHE_BUF_SIZE - _cacheBytesLeft); - _cacheOp = true; + if (_physFilePos != cachePosEnd) { + sioprintf("unexpected _physFilePos %d cache %d %d", _physFilePos, _cacheOfs, _bytesInCache); + _physFilePos = fio.seek(_fd, cachePosEnd, SEEK_SET); + if (_physFilePos != cachePosEnd) { + sioprintf("cache seek error: seek to %d instead of %d, fs = %d", _physFilePos, cachePosEnd, _fileSize); + return; } - } + } + + uint32 cacheDest = (_cacheOfs + _bytesInCache) % CACHE_SIZE; + uint32 cacheRead = CACHE_SIZE - _bytesInCache; + if (cacheDest + cacheRead > CACHE_SIZE) + cacheRead = CACHE_SIZE - cacheDest; + if (cacheRead > MAX_READ_STEP) + cacheRead = MAX_READ_STEP; + + assert(cacheRead); + + _cacheOpRunning = true; + fio.read(_fd, _cacheBuf + cacheDest, cacheRead); } } -void Ps2File::syncCache(void) { - if ((!_forWriting) && _cacheOp) { - int cacheRes = _handle->sync(); - assert(cacheRes >= 0); - _cacheBytesLeft += cacheRes; - _cacheOp = false; +void Ps2ReadFile::cacheReadSync(void) { + if (_cacheOpRunning) { + int res = fio.sync(_fd); + assert(res >= 0); + _bytesInCache += res; + _physFilePos += res; + _cacheOpRunning = false; } } -uint32 Ps2File::read(void *dest, uint32 size) { - assert(!_forWriting); - syncCache(); - if (_seekReset) - seek(0, SEEK_SET); - _readBytesBlock += size; - +uint32 Ps2ReadFile::read(void *dest, uint32 len) { + WaitSema(_sema); uint8 *destBuf = (uint8*)dest; - while (size) { - if (_cacheBytesLeft != 0) { - uint32 doCopy = (size >= _cacheBytesLeft) ? _cacheBytesLeft : size; - memcpy(destBuf, _cachePos, doCopy); - size -= doCopy; - _cacheBytesLeft -= doCopy; - _cachePos += doCopy; - destBuf += doCopy; - _filePos += doCopy; - } - if (size > 0) { - assert(_cacheBytesLeft == 0); - if (size >= CACHE_BUF_SIZE) { - int readRes; - do { - _handle->read(destBuf, size); - readRes = _handle->sync(); - _filePos += readRes; - destBuf += readRes; - size -= readRes; - } while (size && readRes); - if (size) - printf("read operation failed, %d bytes left to read\n", size); - return destBuf - (uint8*)dest; - } else { - uint32 doRead = size; - if ((doRead < 2048) && (_cacheId >= 0)) - doRead = 2048; - memset(_cacheBuf, 'A', 0x20); - _handle->read(_cacheBuf, doRead); - _cacheBytesLeft = _handle->sync(); - _cachePos = _cacheBuf; - if (_cacheBytesLeft == 0) { - return destBuf - (uint8*)dest; - } + if ((_filePos < _cachePos) || (_filePos + len > _cachePos + _bytesInCache)) + cacheReadSync(); // we have to read from CD, sync cache. + + while (len) { + if ((_filePos >= _cachePos) && (_filePos < _cachePos + _bytesInCache)) { // read from cache + uint32 staPos = (_cacheOfs + (_filePos - _cachePos)) % CACHE_SIZE; + uint32 cpyLen = _bytesInCache - (_filePos - _cachePos); + if (cpyLen > len) + cpyLen = len; + if (staPos + cpyLen > CACHE_SIZE) + cpyLen = CACHE_SIZE - staPos; + + assert(cpyLen); + memcpy(destBuf, _cacheBuf + staPos, cpyLen); + _filePos += cpyLen; + destBuf += cpyLen; + _readBytesBlock += len; + len -= cpyLen; + } else { // cache miss + assert(!_cacheOpRunning); + if (_physFilePos != _filePos) { + if ((_filePos < _physFilePos) || (_filePos > _physFilePos + (CACHE_SIZE / 2))) + _readBytesBlock = 0; // reset cache hit count + + if (fio.seek(_fd, _filePos, SEEK_SET) == _filePos) + _physFilePos = _filePos; + else + break; // read beyond EOF } + assert(_physFilePos == _filePos); + int doRead = (len > MAX_READ_STEP) ? MAX_READ_STEP : len; + if (doRead < 2048) + doRead = 2048; + + fio.read(_fd, _cacheBuf, doRead); + _cachePos = _filePos; + _cacheOfs = 0; + _bytesInCache = fio.sync(_fd); + _physFilePos = _filePos + _bytesInCache; + if (!_bytesInCache) + break; // EOF } } - checkCache(); + cacheReadAhead(); + SignalSema(_sema); return destBuf - (uint8*)dest; } -uint32 Ps2File::write(const void *src, uint32 size) { - assert(_forWriting && (!_seekReset)); - const uint8 *srcBuf = (const uint8*)src; +uint32 Ps2ReadFile::write(const void *src, uint32 len) { + sioprintf("write request on Ps2ReadFile!"); + SleepThread(); + return 0; +} + +class Ps2WriteFile : public Ps2File { +public: + Ps2WriteFile(int64 cacheId); + virtual ~Ps2WriteFile(void); + virtual bool open(const char *name); + virtual uint32 read(void *dest, uint32 len); + virtual uint32 write(const void *src, uint32 len); + virtual uint32 tell(void); + virtual uint32 size(void); + virtual int seek(int32 offset, int origin); + virtual bool eof(void); +private: + int _fd; + uint8 *_cacheBuf; + uint32 _filePos, _bytesInCache; +}; + +Ps2WriteFile::Ps2WriteFile(int64 cacheId) : Ps2File(cacheId) { + _fd = -1; + _cacheBuf = (uint8*)malloc(CACHE_SIZE); + _filePos = _bytesInCache = 0; +} + +Ps2WriteFile::~Ps2WriteFile(void) { + if ((_fd >= 0) && (_bytesInCache)) { + fio.write(_fd, _cacheBuf, _bytesInCache); + int wrRes = fio.sync(_fd); + if (wrRes != _bytesInCache) // too late to return an error + printf("Cache flush on fclose(): Unable to write %d cached bytes to mc, only %d bytes written\n", _bytesInCache, wrRes); + } + if (_fd >= 0) + fio.close(_fd); + free(_cacheBuf); +} + +bool Ps2WriteFile::open(const char *name) { + _fd = fio.open(name, O_WRONLY | O_CREAT | O_TRUNC); + return (_fd >= 0); +} +uint32 Ps2WriteFile::read(void *dest, uint32 len) { + printf("ERROR: Read request on Ps2WriteFile\n"); + SleepThread(); + return 0; +} + +uint32 Ps2WriteFile::write(const void *src, uint32 len) { + uint32 size = len; + uint8 *srcBuf = (uint8*)src; while (size) { - uint32 doWrite = (size > _cacheBytesLeft) ? _cacheBytesLeft : size; - memcpy(_cachePos, srcBuf, doWrite); - _cachePos += doWrite; - _cacheBytesLeft -= doWrite; - size -= doWrite; - srcBuf += doWrite; - _filePos += doWrite; - - if (_cacheBytesLeft == 0) { - _handle->write(_cacheBuf, CACHE_BUF_SIZE); - int res = _handle->sync(); - if (res == CACHE_BUF_SIZE) { - _cachePos = _cacheBuf; - _cacheBytesLeft = CACHE_BUF_SIZE; - } else { - printf("cache write operation failed, only %d bytes written\n", res); - return 0; - } + uint32 doCpy = (len > CACHE_SIZE - _bytesInCache) ? (CACHE_SIZE - _bytesInCache) : len; + if (doCpy) { + memcpy(_cacheBuf + _bytesInCache, srcBuf, doCpy); + _bytesInCache += doCpy; + srcBuf += doCpy; + size -= doCpy; + } - if (size >= CACHE_BUF_SIZE) { - int writeRes; - do { - _handle->write(srcBuf, size); - writeRes = _handle->sync(); - _filePos += writeRes; - srcBuf += writeRes; - size -= writeRes; - } while (size && writeRes); - if (size) - printf("write operation failed, %d bytes left to write\n", size); - return srcBuf - (uint8*)src; + if (_bytesInCache == CACHE_SIZE) { + fio.write(_fd, _cacheBuf, _bytesInCache); + int wrRes = fio.sync(_fd); + if (wrRes != _bytesInCache) { + printf("Unable to flush %d cached bytes to memory card!\n", _bytesInCache); + return 0; } + _filePos += _bytesInCache; + _bytesInCache = 0; } } - return srcBuf - (uint8*)src; + return len; +} + +uint32 Ps2WriteFile::tell(void) { + return _bytesInCache + _filePos; } -uint32 Ps2File::tell(void) { - if (_seekReset) - seek(0, SEEK_SET); - return _filePos; +uint32 Ps2WriteFile::size(void) { + return tell(); } -uint32 Ps2File::size(void) { - assert(!_forWriting); - return _fSize; +int Ps2WriteFile::seek(int32 offset, int origin) { + printf("Seek(%d/%d) request on Ps2WriteFile\n", offset, origin); + SleepThread(); + return 0; } -AccessFio *Ps2File::giveHandle(void) { - assert(_handle); - return _handle; +bool Ps2WriteFile::eof(void) { + return true; } +struct TocNode { + char name[64]; + TocNode *next, *sub; + bool isDir; + uint8 nameLen; +}; + +class TocManager { +public: + TocManager(void); + ~TocManager(void); + void readEntries(const char *root); + int64 fileExists(const char *name); + bool haveEntries(void); +private: + void readDir(const char *path, TocNode **node, int level); + TocNode *_rootNode; + char _root[256]; + uint8 _rootLen; +}; + TocManager tocManager; struct FioHandleCache { @@ -415,12 +397,8 @@ struct FioHandleCache { static FioHandleCache *cacheListStart = NULL; static FioHandleCache *cacheListEnd = NULL; static int cacheListLen = 0; +static int openFileCount = 0; static int cacheListSema = -1; -static bool wantHandleCaching = true; - -extern void ps2_disableHandleCaching(void) { - wantHandleCaching = false; -} Ps2File *findInCache(int64 id); @@ -435,42 +413,44 @@ FILE *ps2_fopen(const char *fname, const char *mode) { if (!tocManager.haveEntries() && g_engine) // read the TOC the first time the engine opens a file tocManager.readEntries(g_engine->getGameDataPath()); - int fioMode = 0; - switch(*mode) { - case 'r': - fioMode = O_RDONLY; - break; - case 'w': - fioMode = O_WRONLY | O_CREAT | O_TRUNC; - break; - default: - printf("unsupported mode \"%s\" for file \"%s\"\n", mode, fname); - return NULL; + if (((mode[0] != 'r') && (mode[0] != 'w')) || ((mode[1] != '\0') && (mode[1] != 'b'))) { + printf("unsupported mode \"%s\" for file \"%s\"\n", mode, fname); + return NULL; } + + bool rdOnly = (mode[0] == 'r'); + int64 cacheId = -1; - if ((fioMode == O_RDONLY) && tocManager.haveEntries()) + if (rdOnly && tocManager.haveEntries()) cacheId = tocManager.fileExists(fname); if (cacheId != 0) { Ps2File *file = findInCache(cacheId); - if (file) + if (file) { + //sioprintf("open from cache: %s (%d) [%d]\n", fname, cacheId, file->_handle->_handle); return (FILE*)file; - - if ((mode[1] != 'b') && (mode[1] != '\0')) { - printf("unsupported mode \"%s\" for file \"%s\"\n", mode, fname); - return NULL; } - file = new Ps2File(cacheId); - if (file->open(fname, fioMode)) + + if (rdOnly) { + // smush files need a quite different caching behaviour than normal data files + if (strstr(fname, ".san") || strstr(fname, ".SAN") || strstr(fname, ".San")) + file = new Ps2SmushFile(cacheId); + else + file = new Ps2ReadFile(cacheId); + } else + file = new Ps2WriteFile(cacheId); + + if (file->open(fname)) { + openFileCount++; return (FILE*)file; - else + } else delete file; } return NULL; } void checkCacheListLen(void) { - while (cacheListLen > MAX_CACHED_FILES) { + while ((cacheListLen > MAX_CACHED_FILES) || ((openFileCount > 13) && cacheListLen)) { assert(cacheListEnd && cacheListStart); delete cacheListEnd->file; cacheListEnd->prev->next = NULL; @@ -478,21 +458,24 @@ void checkCacheListLen(void) { cacheListEnd = cacheListEnd->prev; delete temp; cacheListLen--; + openFileCount--; } } int ps2_fclose(FILE *stream) { Ps2File *file = (Ps2File*)stream; - if ((file->_cacheId > 0) && wantHandleCaching) { // this is a file on the CD, could be smart to cache it + if (file->_cacheId > 0) { // this is a file on the CD, could be smart to cache it FioHandleCache *newHandle = new FioHandleCache; newHandle->file = file; - file->setSeekReset(); + file->seek(0, SEEK_SET); WaitSema(cacheListSema); if (!cacheListEnd) { + assert(!cacheListStart); newHandle->prev = newHandle->next = NULL; cacheListEnd = cacheListStart = newHandle; } else { + assert(cacheListStart); newHandle->prev = NULL; newHandle->next = cacheListStart; cacheListStart->prev = newHandle; @@ -501,13 +484,15 @@ int ps2_fclose(FILE *stream) { cacheListLen++; checkCacheListLen(); SignalSema(cacheListSema); - } else + } else { + openFileCount--; delete file; + } return 0; } Ps2File *findInCache(int64 id) { - if ((id <= 0) || !wantHandleCaching) + if (id <= 0) return NULL; WaitSema(cacheListSema); FioHandleCache *node = cacheListStart; @@ -537,11 +522,11 @@ int ps2_fseek(FILE *stream, long offset, int origin) { return ((Ps2File*)stream)->seek(offset, origin); } -long ps2_ftell(FILE *stream) { +uint32 ps2_ftell(FILE *stream) { return ((Ps2File*)stream)->tell(); } -long ps2_fsize(FILE *stream) { +uint32 ps2_fsize(FILE *stream) { return ((Ps2File*)stream)->size(); } diff --git a/backends/ps2/fileio.h b/backends/ps2/fileio.h index 8b9fd431fd..fc10ad8bd8 100644 --- a/backends/ps2/fileio.h +++ b/backends/ps2/fileio.h @@ -24,30 +24,44 @@ #include "scummsys.h" -class AccessFio { +class Ps2File { public: - AccessFio(void); - virtual ~AccessFio(void); - virtual bool open(const char *name, int mode); - virtual void read(void *dest, uint32 size); - virtual void write(const void *src, uint32 size); - virtual int seek(int32 offset, int whence); - virtual int32 sync(void); - virtual bool poll(void); - virtual bool fioAvail(void); -protected: - int _handle; + Ps2File(int64 cacheId); + virtual ~Ps2File(void); + virtual bool open(const char *name) = 0; + virtual uint32 read(void *dest, uint32 len) = 0; + virtual uint32 write(const void *src, uint32 len) = 0; + virtual uint32 tell(void) = 0; + virtual uint32 size(void) = 0; + virtual int seek(int32 offset, int origin) = 0; + virtual bool eof(void) = 0; + int64 _cacheId; +private: }; -class File; +class Ps2SmushFile : public Ps2File { +public: + Ps2SmushFile(int64 cacheId); + virtual ~Ps2SmushFile(void); + virtual bool open(const char *name); + virtual uint32 read(void *dest, uint32 len); + virtual uint32 write(const void *src, uint32 len); + virtual uint32 tell(void); + virtual uint32 size(void); + virtual int seek(int32 offset, int origin); + virtual bool eof(void); +private: + uint32 _filePos, _fileSize; + int _id; +}; FILE *ps2_fopen(const char *fname, const char *mode); int ps2_fclose(FILE *stream); int ps2_fflush(FILE *stream); int ps2_fseek(FILE *stream, long offset, int origin); -long ps2_ftell(FILE *stream); +uint32 ps2_ftell(FILE *stream); int ps2_feof(FILE *stream); -long ps2_fsize(FILE *stream); +uint32 ps2_fsize(FILE *stream); size_t ps2_fread(void *buf, size_t r, size_t n, FILE *stream); int ps2_fgetc(FILE *stream); @@ -58,6 +72,5 @@ int ps2_fputc(int c, FILE *stream); int ps2_fputs(const char *s, FILE *stream); int ps2_fprintf(FILE *pOut, const char *zFormat, ...); -AccessFio *fetchHandle(File *file); - #endif // __PS2FILE_IO__ + diff --git a/backends/ps2/libkbd.cpp b/backends/ps2/libkbd.cpp deleted file mode 100644 index e8b9c1ad41..0000000000 --- a/backends/ps2/libkbd.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. -#----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org -# Licenced under Academic Free License version 2.0 -# Review ps2sdk README & LICENSE files for further details. -# -# $Id$ -# USB Keyboard Driver for PS2 -*/ - - -/* * - * This is the normal Ps2Kbd EE Sourcecode, slightly changed - * and merged into ScummVM's source to work with its - * asynchronous fio. - * - */ - - -#include <tamtypes.h> -#include <fileio.h> -#include "libkbd.h" -#include "backends/ps2/asyncfio.h" - -static int kbd_fd = -1; -static int curr_blockmode = PS2KBD_NONBLOCKING; -static int curr_readmode = PS2KBD_READMODE_NORMAL; - -extern AsyncFio fio; - -int PS2KbdInit(void) -/* Initialise the keyboard library */ -{ - if(kbd_fd >= 0) /* Already initialised */ - { - return 0; - } - - kbd_fd = fio.open(PS2KBD_DEVFILE, 0); - if(kbd_fd < 0) - { - return 0; - } - - return 1; -} - -int PS2KbdRead(char *key) -/* Reads 1 character from the keyboard */ -{ - if((kbd_fd >= 0) && (curr_readmode == PS2KBD_READMODE_NORMAL)) - { - fio.read(kbd_fd, key, 1); - return fio.sync(kbd_fd); - } - - return 0; -} - -int PS2KbdReadRaw(PS2KbdRawKey *key) -/* Reads 1 raw character from the keyboard */ -{ - if((kbd_fd >= 0) && (curr_readmode == PS2KBD_READMODE_RAW)) - { - fio.read(kbd_fd, key, 2); - return fio.sync(kbd_fd) / 2; - } - - return 0; -} - -int PS2KbdSetReadmode(u32 readmode) -/* Sets the read mode to normal or raw */ -{ - if((kbd_fd >= 0) && (curr_readmode != readmode)) - { - curr_readmode = readmode; - return fioIoctl(kbd_fd, PS2KBD_IOCTL_SETREADMODE, &readmode); - } - return 0; -} - -int PS2KbdSetBlockingMode(u32 blockmode) -/* Sets the blocking mode on or off */ -{ - if((kbd_fd >= 0) && (curr_blockmode != blockmode)) - { - return fioIoctl(kbd_fd, PS2KBD_IOCTL_SETBLOCKMODE, &blockmode); - } - - return 0; -} - -int PS2KbdSetRepeatRate(u32 repeat) -/* Sets the repeat rate in millseconds */ -{ - if(kbd_fd >= 0) - { - return fioIoctl(kbd_fd, PS2KBD_IOCTL_SETREPEATRATE, &repeat); - } - return 0; -} - -int PS2KbdSetLeds(u8 leds) -/* Sets all connected keyboards leds */ -{ - if(kbd_fd >= 0) - { - return fioIoctl(kbd_fd, PS2KBD_IOCTL_SETLEDS, &leds); - } - return 0; -} - -int PS2KbdSetKeymap(PS2KbdKeyMap *keymaps) -/* Sets the current keymap */ -{ - if(kbd_fd >= 0) - { - return fioIoctl(kbd_fd, PS2KBD_IOCTL_SETKEYMAP, keymaps); - } - return 0; -} - -int PS2KbdSetCtrlmap(u8 *ctrlmap) -/* Sets the control key mappings */ -{ - if(kbd_fd >= 0) - { - return fioIoctl(kbd_fd, PS2KBD_IOCTL_SETCTRLMAP, ctrlmap); - } - return 0; -} - -int PS2KbdSetAltmap(u8 *altmap) -/* Sets the alt key mappings */ -{ - if(kbd_fd >= 0) - { - return fioIoctl(kbd_fd, PS2KBD_IOCTL_SETALTMAP, altmap); - } - return 0; -} - -int PS2KbdSetSpecialmap(u8 *special) -/* Sets the special key mappings */ -{ - if(kbd_fd >= 0) - { - return fioIoctl(kbd_fd, PS2KBD_IOCTL_SETSPECIALMAP, special); - } - return 0; -} - -int PS2KbdFlushBuffer(void) -/* Flushes the keyboard buffer */ -{ - int dummy; - - if(kbd_fd >= 0) - { - return fioIoctl(kbd_fd, PS2KBD_IOCTL_FLUSHBUFFER, &dummy); - } - return 0; -} - -int PS2KbdResetKeymap(void) -/* Resets the keymap to the default US mapping */ -{ - int dummy; - - if(kbd_fd >= 0) - { - return fioIoctl(kbd_fd, PS2KBD_IOCTL_RESETKEYMAP, &dummy); - } - return 0; -} - -int PS2KbdClose(void) -/* Close down the keyboard library */ -{ - if(kbd_fd >= 0) - { - fio.close(kbd_fd); - kbd_fd = -1; - } - - return 1; -} diff --git a/backends/ps2/ps2input.cpp b/backends/ps2/ps2input.cpp index 9fbf411b6e..f2092a4030 100644 --- a/backends/ps2/ps2input.cpp +++ b/backends/ps2/ps2input.cpp @@ -23,7 +23,7 @@ #include <malloc.h> #include <assert.h> #include <libmouse.h> -#include <libkbd.h> +#include "backends/ps2/rpckbd.h" #include "backends/ps2/ps2input.h" #include "backends/ps2/ps2pad.h" #include "backends/ps2/systemps2.h" @@ -54,7 +54,6 @@ Ps2Input::Ps2Input(OSystem_PS2 *system, bool mouseLoaded, bool kbdLoaded) { if (_kbdLoaded) { if (PS2KbdInit() >= 0) { PS2KbdSetReadmode(PS2KBD_READMODE_RAW); - PS2KbdSetBlockingMode(PS2KBD_NONBLOCKING); printf("PS2Kbd initialized\n"); } else { printf("unable to initialize PS2Kbd!\n"); diff --git a/backends/ps2/ps2pad.cpp b/backends/ps2/ps2pad.cpp index 76a6d8658c..599030f489 100644 --- a/backends/ps2/ps2pad.cpp +++ b/backends/ps2/ps2pad.cpp @@ -111,17 +111,9 @@ void Ps2Pad::initPad(void) { } } -bool Ps2Pad::checkPadReady(int port, int slot, uint32 wait, uint32 *waitRes) { - int state; - for (uint32 cnt = 0; cnt < wait; cnt++) { - state = padGetState(port, slot); - if ((state == PAD_STATE_STABLE) || (state == PAD_STATE_FINDCTP1)) { - if (waitRes) - *waitRes = cnt; - return true; - } - } - return false; +bool Ps2Pad::checkPadReady(int port, int slot) { + int state = padGetState(port, slot); + return (state == PAD_STATE_STABLE) || (state == PAD_STATE_FINDCTP1); } bool Ps2Pad::padAlive(void) { @@ -152,4 +144,3 @@ void Ps2Pad::readPad(uint16 *pbuttons, int16 *joyh, int16 *joyv) { } - diff --git a/backends/ps2/ps2pad.h b/backends/ps2/ps2pad.h index 1e1eb08e87..12baebdc3f 100644 --- a/backends/ps2/ps2pad.h +++ b/backends/ps2/ps2pad.h @@ -49,7 +49,7 @@ public: void readPad(uint16 *pbuttons, int16 *joyh, int16 *joyv); private: void initPad(void); - bool checkPadReady(int port, int slot, uint32 wait = 1, uint32 *waitRes = NULL); + bool checkPadReady(int port, int slot); OSystem_PS2 *_system; int _port, _slot; diff --git a/backends/ps2/savefile.cpp b/backends/ps2/savefile.cpp index 78def68d7b..1449c94510 100644 --- a/backends/ps2/savefile.cpp +++ b/backends/ps2/savefile.cpp @@ -19,9 +19,6 @@ * */ -#include "backends/ps2/savefile.h" -#include "backends/ps2/Gs2dScreen.h" - #include <tamtypes.h> #include <kernel.h> #include <sifrpc.h> @@ -29,69 +26,76 @@ #include <fileio.h> #include <malloc.h> #include <ucl/ucl.h> +#include "backends/ps2/savefile.h" +#include "backends/ps2/Gs2dScreen.h" +#include "backends/ps2/asyncfio.h" +#include "backends/ps2/systemps2.h" #include "scummsys.h" -class StdioSaveFile : public SaveFile { +extern AsyncFio fio; + +class UclOutSaveFile : public Common::WriteStream { public: - StdioSaveFile(const char *filename, bool saveOrLoad); - virtual ~StdioSaveFile(); - virtual bool isOpen() const; - virtual uint32 read(void *buf, uint32 cnt); - virtual uint32 write(const void *buf, uint32 cnt); + UclOutSaveFile(const char *filename, Gs2dScreen *screen); + virtual ~UclOutSaveFile(void); + virtual uint32 write(const void *ptr, uint32 size); + virtual int flush(void); + virtual bool ioFailed(void); + virtual void clearIOFailed(void); private: - FILE *_fh; - bool _saving; + Gs2dScreen *_screen; + int _fd; + uint8 *_buf; + uint32 _bufSize, _bufPos; + bool _ioFailed; }; -class UclSaveFile : public SaveFile { +class UclInSaveFile : public Common::ReadStream { public: - UclSaveFile(const char *filename, bool saveOrLoad, Gs2dScreen *screen); - virtual ~UclSaveFile(); - virtual bool isOpen() const; - virtual uint32 read(void *buf, uint32 cnt); - virtual uint32 write(const void *buf, uint32 cnt); + UclInSaveFile(const char *filename, Gs2dScreen *screen); + virtual ~UclInSaveFile(void); + virtual bool eos(void) const; + virtual uint32 read(void *ptr, uint32 size); + virtual bool ioFailed(void); + virtual void clearIOFailed(void); private: Gs2dScreen *_screen; - FILE *_fh; - bool _saving; uint8 *_buf; uint32 _bufSize, _bufPos; + bool _ioFailed; }; -#define ARRAY_ENTRIES 16 -static mcTable mcDir[ARRAY_ENTRIES] __attribute__((aligned(64))); -static int mcEntries; -static bool mcNeedUpdate = true; +#define MAX_MC_ENTRIES 16 -Ps2SaveFileManager::Ps2SaveFileManager(const char *path, SaveMode mode, Gs2dScreen *screen) { +Ps2SaveFileManager::Ps2SaveFileManager(OSystem_PS2 *system, Gs2dScreen *screen) { + _system = system; _screen = screen; - if (mcInit(MC_TYPE_MC) < 0) { - printf("Can't init libmc!\n"); - SleepThread(); - } - - if (path) - strcpy(_savePath, path); - else - _savePath[0] = '\0'; + assert(mcInit(MC_TYPE_MC) >= 0); + + _mcDirList = (mcTable*)memalign(64, MAX_MC_ENTRIES * sizeof(mcTable)); + _mcDirName[0] = '\0'; + _mcCheckTime = 0; + _mcNeedsUpdate = true; + + int mcCheckCount; + int res = -10; + for (int mcCheckCount = 0; mcCheckCount < 3; mcCheckCount++) { + /* retry mcGetInfo 3 times. It slows down startup without mc considerably, + but cheap 3rd party memory cards apparently fail to get detected once in a while */ - _mode = mode; - if (mode == TO_HOST) { - printf("saving to host:/\n"); - } else if (mode == TO_MC) { int mcType, mcFree, mcFormat, res; mcGetInfo(0, 0, &mcType, &mcFree, &mcFormat); mcSync(0, NULL, &res); - if ((res == 0) || (res == -1)) // mc okay + if ((res == 0) || (res == -1)) { // mc okay + _mcPresent = true; printf("MC okay, result = %d. Type %d, Free %d, Format %d\n", res, mcType, mcFree, mcFormat); - else + checkMainDirectory(); + break; + } else { + _mcPresent = false; printf("MC failed, not present or not formatted, code %d\n", res); - } else { - printf("HDD not implemented yet\n"); - SleepThread(); + } } - - checkMainDirectory(); } Ps2SaveFileManager::~Ps2SaveFileManager(void) { @@ -100,130 +104,177 @@ Ps2SaveFileManager::~Ps2SaveFileManager(void) { void Ps2SaveFileManager::checkMainDirectory(void) { // verify that the main directory (scummvm config + icon) exists int ret; - mcGetDir(0, 0, "/ScummVM/*", 0, ARRAY_ENTRIES, mcDir); + mcGetDir(0, 0, "/ScummVM/*", 0, MAX_MC_ENTRIES, _mcDirList); mcSync(0, NULL, &ret); printf("/ScummVM/* res = %d\n", ret); if (ret <= 0) { // assume directory doesn't exist printf("Dir doesn't exist\n"); - fioMkdir("mc0:ScummVM"); - FILE *outf = fopen("mc0:ScummVM/scummvm.icn", "wb"); - if (outf) { + fio.mkdir("mc0:ScummVM"); + int fd = fio.open("mc0:ScummVM/scummvm.icn", O_WRONLY | O_CREAT | O_TRUNC); + if (fd >= 0) { uint16 icoSize; uint16 *icoBuf = decompressIconData(&icoSize); - fwrite(icoBuf, 2, icoSize, outf); - fclose(outf); - printf(".icn written\n"); + fio.write(fd, icoBuf, icoSize * 2); + fio.sync(fd); free(icoBuf); - + fio.close(fd); + printf(".icn written\n"); setupIcon("mc0:ScummVM/icon.sys", "scummvm.icn", "ScummVM", "Configuration"); } else printf("unable to write icon data\n"); } } -SaveFile *Ps2SaveFileManager::openSavefile(const char *filename, bool saveOrLoad) { - char *defaultExt = "SAVE"; - char nameBase[256]; - strcpy(nameBase, filename); - char *ext = strchr(nameBase, '.'); - if (ext) { +void Ps2SaveFileManager::splitPath(const char *fileName, char *dir, char *name) { + strcpy(dir, fileName); + char *ext = strchr(dir, '.'); + if (ext) { *ext = '\0'; ext++; - if (!*ext) - ext = defaultExt; - } else - ext = defaultExt; - - if (_mode == TO_HOST) { - char hostName[256]; - sprintf(hostName, "%s%s", _savePath, filename); - SaveFile *res = new StdioSaveFile(hostName, saveOrLoad); - if (!res->isOpen()) { - printf("unable to open savefile %s for %s\n", hostName, saveOrLoad ? "saving" : "loading"); - delete res; - return NULL; - } - printf("Savefile %s opened for %s\n", hostName, saveOrLoad ? "saving" : "loading"); - return res; - } else if (_mode == TO_MC) { - _screen->wantAnim(true); + } + if (ext && *ext) + sprintf(name, "%s.ucl", ext); + else + strcpy(name, "save.ucl"); +} + +bool Ps2SaveFileManager::mcReadyForDir(const char *dir) { + if (_mcNeedsUpdate || ((_system->getMillis() - _mcCheckTime) > 1000) || !_mcPresent) { + // check if memory card was exchanged/removed in the meantime int mcType, mcFree, mcFormat, mcResult; mcGetInfo(0, 0, &mcType, &mcFree, &mcFormat); mcSync(0, NULL, &mcResult); - if (mcResult == -1) // memory card was exchanged - mcNeedUpdate = true; - else if (mcResult != 0) { - printf("Memory card is not ready\n"); - return NULL; + if (mcResult != 0) { // memory card was exchanged + _mcNeedsUpdate = true; + if (mcResult != -1) { + _mcPresent = false; + printf("MC not found, error code %d\n", mcResult); + return false; + } } - + _mcPresent = true; + } + if (_mcNeedsUpdate || strcmp(_mcDirName, dir)) { + strcpy(_mcDirName, dir); char dirStr[256]; - sprintf(dirStr, "/ScummVM-%s/*", nameBase); - if (saveOrLoad) { // saving - mcGetDir(0, 0, dirStr, 0, ARRAY_ENTRIES, mcDir); - mcSync(0, NULL, &mcEntries); - mcNeedUpdate = true; - if (mcEntries <= 0) { // directory is empty or doesn't exist. - sprintf(dirStr, "mc0:ScummVM-%s", nameBase); - printf("Creating directory %s\n", dirStr); - if (mcEntries < 0) { // directory doesn't exist - if (fioMkdir(dirStr) < 0) { - printf("unable to create directory %s\n", dirStr); - _screen->wantAnim(false); - return NULL; // unable to create directory - } - } - char icoSysDest[256], saveDesc[256]; - sprintf(icoSysDest, "%s/icon.sys", dirStr); - strcpy(saveDesc, nameBase); - if ((saveDesc[0] >= 'a') && (saveDesc[0] <= 'z')) - saveDesc[0] += 'A' - 'a'; - setupIcon(icoSysDest, "../ScummVM/scummvm.icn", saveDesc, "Savegames"); - } - } else { - // scumm engine tries to open hundreds of files to search for savegames. - if (mcNeedUpdate) { - mcGetDir(0, 0, dirStr, 0, ARRAY_ENTRIES, mcDir); - mcSync(0, NULL, &mcEntries); - mcNeedUpdate = false; - } - bool fileExists = false; - char searchName[32]; - sprintf(searchName, "%s.bin", ext); - for (int cnt = 0; (cnt < mcEntries) && !fileExists; cnt++) - if (strcmp(searchName, (char*)mcDir[cnt].name) == 0) - fileExists = true; - - if (!fileExists) { - _screen->wantAnim(false); - return NULL; + sprintf(dirStr, "/ScummVM-%s/*", dir); + mcGetDir(0, 0, dirStr, 0, MAX_MC_ENTRIES, _mcDirList); + mcSync(0, NULL, &_mcEntries); + return (_mcEntries >= 0); + } else + return true; +} + +InSaveFile *Ps2SaveFileManager::openForLoading(const char *filename) { + _screen->wantAnim(true); + + char dir[256], name[256]; + splitPath(filename, dir, name); + if (mcReadyForDir(dir)) { + bool fileExists = false; + for (int i = 0; i < _mcEntries; i++) + if (strcmp(name, (char*)_mcDirList[i].name) == 0) + fileExists = true; + if (fileExists) { + char fullName[256]; + sprintf(fullName, "mc0:ScummVM-%s/%s", dir, name); + UclInSaveFile *file = new UclInSaveFile(fullName, _screen); + if (file) { + if (!file->ioFailed()) { + return (InSaveFile*)file; + } else + delete file; } - } - sprintf(dirStr, "mc0:ScummVM-%s/%s.bin", nameBase, ext); - SaveFile *file = new UclSaveFile(dirStr, saveOrLoad, _screen); - if (!file->isOpen()) { - printf("unable to open savefile %s for %s\n", dirStr, saveOrLoad ? "saving" : "loading"); - delete file; - _screen->wantAnim(false); - return NULL; - } - return file; - } else { - printf("HDD not implemented yet\n"); - return NULL; + } else + printf("file %s (%s) doesn't exist\n", filename, name); } + _screen->wantAnim(false); + return NULL; } -void Ps2SaveFileManager::listSavefiles(const char * /* prefix */, bool *marks, int num) { - memset(marks, true, num * sizeof(bool)); +OutSaveFile *Ps2SaveFileManager::openForSaving(const char *filename) { + _screen->wantAnim(true); + char dir[256], name[256]; + splitPath(filename, dir, name); + + if (!mcReadyForDir(dir)) { + if (_mcPresent) { // directory doesn't seem to exist yet + char fullPath[256]; + sprintf(fullPath, "mc0:ScummVM-%s", dir); + fio.mkdir(fullPath); + + char icoSysDest[256], saveDesc[256]; + sprintf(icoSysDest, "%s/icon.sys", fullPath); + strcpy(saveDesc, dir); + if ((saveDesc[0] >= 'a') && (saveDesc[0] <= 'z')) + saveDesc[0] += 'A' - 'a'; + setupIcon(icoSysDest, "../ScummVM/scummvm.icn", saveDesc, "Savegames"); + } + } + + if (_mcPresent) { + char fullPath[256]; + sprintf(fullPath, "mc0:ScummVM-%s/%s", dir, name); + UclOutSaveFile *file = new UclOutSaveFile(fullPath, _screen); + if (!file->ioFailed()) { + // we're creating a file, mc will have to be updated next time + _mcNeedsUpdate = true; + return (OutSaveFile*)file; + } else + delete file; + } + + _screen->wantAnim(false); + return NULL; } -const char *Ps2SaveFileManager::getSavePath(void) const { - return _savePath; +void Ps2SaveFileManager::listSavefiles(const char *prefix, bool *marks, int num) { + _screen->wantAnim(true); + + int mcType, mcFree, mcFormat, mcResult; + mcGetInfo(0, 0, &mcType, &mcFree, &mcFormat); + mcSync(0, NULL, &mcResult); + + memset(marks, false, num * sizeof(bool)); + + if ((mcResult == 0) || (mcResult == -1)) { + // there's a memory card in the slot. + if (mcResult == -1) + _mcNeedsUpdate = true; + + mcTable *mcEntries = (mcTable*)memalign(64, sizeof(mcTable) * MAX_MC_ENTRIES); + + char dirStr[256], ext[256], mcSearchStr[256]; + strcpy(dirStr, prefix); + char *pos = strchr(dirStr, '.'); + if (pos) { + strcpy(ext, pos + 1); + *pos = '\0'; + } else + ext[0] = '\0'; + sprintf(mcSearchStr, "/ScummVM-%s/%s*", dirStr, ext); + + int numEntries; + mcGetDir(0, 0, mcSearchStr, 0, MAX_MC_ENTRIES, mcEntries); + mcSync(0, NULL, &numEntries); + + int searchLen = strlen(ext); + for (int i = 0; i < numEntries; i++) + if ((((char*)mcEntries[i].name)[0] != '.') && stricmp((char*)mcEntries[i].name, "icon.sys")) { + char *stopCh; + int destNum = (int)strtoul((char*)mcEntries[i].name + searchLen, &stopCh, 10); + if ((!stopCh) || strcmp(stopCh, ".ucl")) + printf("unexpected end %s in name %s, search %s\n", stopCh, (char*)mcEntries[i].name, prefix); + if (destNum < num) + marks[destNum] = true; + } + free(mcEntries); + } + _screen->wantAnim(false); } -void Ps2SaveFileManager::setSavePath(const char *path) { - strcpy(_savePath, path); +const char *Ps2SaveFileManager::getSavePath(void) const { + return "mc0:"; } bool Ps2SaveFileManager::setupIcon(const char *dest, const char *ico, const char *descr1, const char *descr2) { @@ -231,9 +282,14 @@ bool Ps2SaveFileManager::setupIcon(const char *dest, const char *ico, const char memset(&icon_sys, 0, sizeof(mcIcon)); memcpy(icon_sys.head, "PS2D", 4); char title[256]; - sprintf(title, "%s\n%s", descr1, descr2); + if (!stricmp("SAVEGAME", descr1)) { // these are broken sword 1 savegames + sprintf(title, "BSword1\n%s", descr2); + icon_sys.nlOffset = 8; + } else { + sprintf(title, "%s\n%s", descr1, descr2); + icon_sys.nlOffset = strlen(descr1) + 1; + } strcpy_sjis((short*)&(icon_sys.title), title); - icon_sys.nlOffset = strlen(descr1) + 1; icon_sys.trans = 0x10; memcpy(icon_sys.bgCol, _bgcolor, sizeof(_bgcolor)); memcpy(icon_sys.lightDir, _lightdir, sizeof(_lightdir)); @@ -243,11 +299,12 @@ bool Ps2SaveFileManager::setupIcon(const char *dest, const char *ico, const char strcpy((char*)icon_sys.copy, ico); strcpy((char*)icon_sys.del, ico); - FILE *outf = fopen(dest, "wb"); - if (outf) { - fwrite(&icon_sys, 1, sizeof(icon_sys), outf); - fclose(outf); - return true; + int fd = fio.open(dest, O_WRONLY | O_CREAT | O_TRUNC); + if (fd >= 0) { + fio.write(fd, &icon_sys, sizeof(icon_sys)); + int res = fio.sync(fd); + fio.close(fd); + return (res == sizeof(icon_sys)); } else return false; } @@ -256,7 +313,7 @@ uint16 *Ps2SaveFileManager::decompressIconData(uint16 *size) { uint16 inPos = 1; uint16 *rleData = (uint16*)_rleIcoData; uint16 resSize = rleData[0]; - uint16 *resData = (uint16*)malloc(resSize * sizeof(uint16*)); + uint16 *resData = (uint16*)malloc(resSize * sizeof(uint16)); uint16 outPos = 0; while (outPos < resSize) { uint16 len = rleData[inPos++]; @@ -271,105 +328,148 @@ uint16 *Ps2SaveFileManager::decompressIconData(uint16 *size) { return resData; } +UclInSaveFile::UclInSaveFile(const char *filename, Gs2dScreen *screen) { + _screen = screen; + int fd = fio.open(filename, O_RDONLY); + _buf = NULL; + _bufSize = _bufPos = 0; + _ioFailed = false; + + if (fd >= 0) { + int srcSize = fio.seek(fd, 0, SEEK_END); + fio.seek(fd, 0, SEEK_SET); + if (srcSize > 4) { + int res; + uint8 *tmpBuf = (uint8*)malloc(srcSize); + fio.read(fd, tmpBuf, srcSize); + res = fio.sync(fd); + if (res == srcSize) { + uint32 resLen = _bufSize = *(uint32*)tmpBuf; + _buf = (uint8*)malloc(_bufSize + 2048); + res = ucl_nrv2e_decompress_8(tmpBuf + 4, srcSize - 4, _buf, &resLen, NULL); + if ((res < 0) || (resLen != _bufSize)) { + printf("Unable to decompress file %s (%d -> %d) error code %d\n", filename, srcSize, _bufSize, res); + free(_buf); + _buf = NULL; + _bufSize = 0; + } + } + free(tmpBuf); + } + if (!_buf) { + printf("Invalid savegame %s\n", filename); + _ioFailed = true; + } + fio.close(fd); + } +} -StdioSaveFile::StdioSaveFile(const char *filename, bool saveOrLoad) { - _fh = ::fopen(filename, (saveOrLoad? "wb" : "rb")); - _saving = saveOrLoad; +UclInSaveFile::~UclInSaveFile(void) { + if (_buf) + free(_buf); + _screen->wantAnim(false); } -StdioSaveFile::~StdioSaveFile(void) { - if (_fh) - ::fclose(_fh); +bool UclInSaveFile::ioFailed(void) { + return _ioFailed; } -bool StdioSaveFile::isOpen(void) const { - return _fh != NULL; +void UclInSaveFile::clearIOFailed(void) { + _ioFailed = false; } -uint32 StdioSaveFile::read(void *buf, uint32 cnt) { - assert(!_saving); - return ::fread(buf, 1, cnt, _fh); +bool UclInSaveFile::eos(void) const { + return _bufPos == _bufSize; } -uint32 StdioSaveFile::write(const void *buf, uint32 cnt) { - assert(_saving); - return ::fwrite(buf, 1, cnt, _fh); +uint32 UclInSaveFile::read(void *ptr, uint32 size) { + uint32 bytesRemain = _bufSize - _bufPos; + if (size > bytesRemain) { + size = bytesRemain; + _ioFailed = true; + } + memcpy(ptr, _buf + _bufPos, size); + _bufPos += size; + return size; } -UclSaveFile::UclSaveFile(const char *filename, bool saveOrLoad, Gs2dScreen *screen) { - _fh = ::fopen(filename, (saveOrLoad? "wb" : "rb")); - _saving = saveOrLoad; - _bufPos = 0; +UclOutSaveFile::UclOutSaveFile(const char *filename, Gs2dScreen *screen) { _screen = screen; - if (_fh) { - if (_saving) { - _buf = (uint8*)malloc(65536); - _bufSize = 65536; - } else { - uint32 srcSize = ::fsize(_fh); - uint8 *srcBuf = (uint8*)malloc(srcSize); - int res = ::fread(srcBuf, 1, srcSize, _fh); - assert(res == srcSize); - - uint32 resLen = _bufSize = *(uint32*)srcBuf; - _buf = (uint8*)malloc(_bufSize + 2048); - res = ucl_nrv2e_decompress_8(srcBuf + 4, srcSize - 4, _buf, &resLen, NULL); - if ((res < 0) || (resLen != _bufSize)) { - printf("Unable to decompress file %s (%d -> %d) error code %d\n", filename, srcSize, _bufSize, res); - free(_buf); - _buf = NULL; - _bufSize = 0; - } - ::fclose(_fh); - _fh = NULL; - free(srcBuf); - } + _bufPos = 0; + _fd = fio.open(filename, O_WRONLY | O_CREAT | O_TRUNC); + if (_fd >= 0) { + _bufSize = 65536; + _buf = (uint8*)malloc(_bufSize); + _ioFailed = false; } else { - printf("Savefile %s doesn't exist\n", filename); + _ioFailed = true; + _bufSize = 0; _buf = NULL; } } -UclSaveFile::~UclSaveFile(void) { - if (_saving) { +UclOutSaveFile::~UclOutSaveFile(void) { + if (_buf) { + if (flush() < 0) + printf("~UclOutSaveFile: Flush failed!\n"); + free(_buf); + } + if (_fd >= 0) + fio.close(_fd); + _screen->wantAnim(false); +} + +bool UclOutSaveFile::ioFailed(void) { + return _ioFailed; +} + +void UclOutSaveFile::clearIOFailed(void) { + _ioFailed = false; +} + +int UclOutSaveFile::flush(void) { + if (_bufPos == 0) + return 0; // no data to flush + if (_buf) { uint8 *compBuf = (uint8*)malloc(_bufPos * 2); uint32 compSize = _bufPos * 2; int res = ucl_nrv2e_99_compress(_buf, _bufPos, compBuf, &compSize, NULL, 10, NULL, NULL); if (res >= 0) { - fwrite(&_bufPos, 1, 4, _fh); - fwrite(compBuf, 1, compSize, _fh); - } else { - printf("unable to compress %d bytes of savedata, errorcode %d\n", _bufPos, res); + fio.write(_fd, &_bufPos, 4); + if (fio.sync(_fd) == 4) { + fio.write(_fd, compBuf, compSize); + if (fio.sync(_fd) != compSize) + res = -1; + } else + res = -1; + } else + printf("Unable to compress %d bytes of savedata, errorcode %d\n", _bufPos, res); + free(compBuf); + + if (res >= 0) { + _bufPos = 0; + return 0; } - free(compBuf); } - if (_buf) - free(_buf); - if (_fh) - ::fclose(_fh); - _screen->wantAnim(false); -} - -bool UclSaveFile::isOpen(void) const { - return (_buf != NULL); + _ioFailed = true; + printf("UclOutSaveFile::flush failed!\n"); + return -1; } -uint32 UclSaveFile::read(void *buf, uint32 cnt) { - assert(!_saving); - uint32 numBytes = (cnt > _bufSize - _bufPos) ? (_bufSize - _bufPos) : cnt; - memcpy(buf, _buf + _bufPos, numBytes); - _bufPos += numBytes; - return numBytes; -} -uint32 UclSaveFile::write(const void *buf, uint32 cnt) { - assert(_saving); - if (_bufSize - _bufPos < cnt) { - _bufSize += (cnt > 65536) ? cnt : 65536; +uint32 UclOutSaveFile::write(const void *ptr, uint32 size) { + assert(_bufPos <= _bufSize); + uint32 bytesFree = _bufSize - _bufPos; + if (bytesFree < size) { + uint32 allocBytes = (size > 32 * 1024) ? size : 32 * 1024; + _bufSize += allocBytes; _buf = (uint8*)realloc(_buf, _bufSize); + bytesFree = _bufSize - _bufPos; } - memcpy(_buf + _bufPos, buf, cnt); - _bufPos += cnt; - return cnt; + assert(bytesFree >= size); + memcpy(_buf + _bufPos, ptr, size); + _bufPos += size; + return size; } + diff --git a/backends/ps2/savefile.h b/backends/ps2/savefile.h index 25133e90dc..66d27f1bbb 100644 --- a/backends/ps2/savefile.h +++ b/backends/ps2/savefile.h @@ -32,42 +32,40 @@ enum SaveMode { }; class Gs2dScreen; +class OSystem_PS2; class Ps2SaveFileManager : public SaveFileManager { public: - Ps2SaveFileManager(const char *path, SaveMode mode, Gs2dScreen *screen); + Ps2SaveFileManager(OSystem_PS2 *system, Gs2dScreen *screen); virtual ~Ps2SaveFileManager(); - - virtual SaveFile *openForSaving(const char *filename) { - return openSavefile(filename, true); - } - virtual SaveFile *openForLoading(const char *filename) { - return openSavefile(filename, false); - } - - virtual void listSavefiles(const char * /* prefix */, bool *marks, int num); + virtual InSaveFile *openForLoading(const char *filename); + virtual OutSaveFile *openForSaving(const char *filename); + virtual void listSavefiles(const char *prefix, bool *marks, int num); /** Get the path to the save game directory. */ virtual const char *getSavePath() const; - - void setSavePath(const char *path); +private: static bool setupIcon(const char *dest, const char *ico, const char *descr1, const char *descr2); + bool mcReadyForDir(const char *dir); + void checkMainDirectory(void); -private: + void splitPath(const char *fileName, char *dir, char *name); uint16 *decompressIconData(uint16 *size); Gs2dScreen *_screen; + OSystem_PS2 *_system; - static const uint8 _rleIcoData[14018]; - SaveMode _mode; - char _savePath[256]; + mcTable *_mcDirList; + int _mcEntries; + char _mcDirName[256]; + bool _mcNeedsUpdate, _mcPresent; + uint32 _mcCheckTime; + static const uint8 _rleIcoData[14018]; static const iconIVECTOR _bgcolor[4]; static const iconFVECTOR _lightdir[3], _lightcol[3], _ambient; - - SaveFile *openSavefile(const char *filename, bool saveOrLoad); }; #endif // __PS2_SAVEFILE__ diff --git a/backends/ps2/sjpcm.h b/backends/ps2/sjpcm.h deleted file mode 100644 index d6cf95ec86..0000000000 --- a/backends/ps2/sjpcm.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - ----------------------------------------------------------------------- - sjpcm.h - SjPCM EE-side prototypes. (c) Nick Van Veen (aka Sjeep), 2002 - ----------------------------------------------------------------------- - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef _SJPCM_H -#define _SJPCM_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define SJPCM_IRX 0xB0110C5 -#define SJPCM_PUTS 0x01 -#define SJPCM_INIT 0x02 -#define SJPCM_PLAY 0x03 -#define SJPCM_PAUSE 0x04 -#define SJPCM_SETVOL 0x05 -#define SJPCM_ENQUEUE 0x06 -#define SJPCM_CLEARBUFF 0x07 -#define SJPCM_QUIT 0x08 -#define SJPCM_GETAVAIL 0x09 -#define SJPCM_GETBUFFD 0x10 - -void SjPCM_Puts(char *format, ...); -int SjPCM_Init(int sync); -void SjPCM_Enqueue(short *left, short *right, int size, int wait); -void SjPCM_Play(); -void SjPCM_Pause(); -void SjPCM_Setvol(unsigned int volume); -void SjPCM_Clearbuff(); -int SjPCM_Available(); -int SjPCM_Buffered(); -void SjPCM_Quit(); - -#ifdef __cplusplus -} -#endif - -#endif // _SJPCM_H diff --git a/backends/ps2/smushio.cpp b/backends/ps2/smushio.cpp new file mode 100644 index 0000000000..ef7c9f4517 --- /dev/null +++ b/backends/ps2/smushio.cpp @@ -0,0 +1,376 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +/* + The Smush player uses at least two handles for accessing the same SMUSH file, + to avoid threading issues. One handle for video, one for audio apparently. + Each of the handles always skips the data that the other one read before + (or will read later). + + This behaviour makes it difficult to do read ahead caching without reading + any given file twice, so this class tries to "reunite" the read accesses and + do the necessary caching. +*/ + +#include "backends/ps2/fileio.h" +#include "backends/ps2/asyncfio.h" +#include <kernel.h> +#include <assert.h> +#include <string.h> +#include <sio.h> + +extern AsyncFio fio; +extern void sioprintf(const char *zFormat, ...); + +#define SMUSH_CACHE_SIZE (5 * 1024 * 1024) +#define READ_STEP (32 * 1024) +#define SMUSH_IN_USE -2 + +class SmushReader { +public: + SmushReader(void); + ~SmushReader(void); + int open(const char *name); + void close(void); + uint32 read(void *dest, uint32 from, uint32 len); + void virtSeek(uint32 from, uint32 to); + uint32 size(void); + bool keepOpened(void); +private: + void processCache(bool sync); + char _fname[256]; + int _sema, _fd, _refCount; + uint8 *_cacheBuf; + volatile uint32 _cacheFilePos, _bytesInCache, _fileSize, _cacheBufOfs; + volatile uint32 _lastRead[2]; + volatile bool _cacheOp; +}; + +SmushReader::SmushReader(void) { + _cacheBuf = NULL; + _fd = -1; + _refCount = 0; + + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + _sema = CreateSema(&newSema); + assert(_sema >= 0); +} + +SmushReader::~SmushReader(void) { + DeleteSema(_sema); +} + +int SmushReader::open(const char *name) { + WaitSema(_sema); + if (_refCount) { + if (stricmp(_fname, name)) { + sioprintf("SmushReader is already open to file\n%s\nGot open request for %s", _fname, name); + SignalSema(_sema); + return SMUSH_IN_USE; + } + } else { + assert(_fd < 0); + _fd = fio.open(name, O_RDONLY); + if (_fd < 0) { + SignalSema(_sema); + return -1; + } + _fileSize = fio.seek(_fd, 0, SEEK_END); + fio.seek(_fd, 0, SEEK_SET); + + _cacheBuf = (uint8*)malloc(SMUSH_CACHE_SIZE); + if (!_cacheBuf) { + sioprintf("Smush Reader ran out of memory"); + fio.close(_fd); + _fd = -1; + SignalSema(_sema); + return -1; + } + _lastRead[0] = _lastRead[1] = 0; + _cacheBufOfs = _bytesInCache = _cacheFilePos = 0; + fio.read(_fd, _cacheBuf, READ_STEP); + _cacheOp = true; + strcpy(_fname, name); + } + _refCount++; + sioprintf("SmushReader %s ref count %d", _fname, _refCount); + SignalSema(_sema); + return 0; +} + +void SmushReader::close(void) { + WaitSema(_sema); + sioprintf("Closing Ref to %s", _fname); + assert(_refCount > 0); + _refCount--; + if (!_refCount) { + sioprintf("SmushReader: All references to %s closed", _fname); + processCache(true); + _fname[0] = '\0'; + fio.close(_fd); + _fd = -1; + free(_cacheBuf); + _cacheBuf = NULL; + } + SignalSema(_sema); +} + +#define MIN(a, b) ((a < b) ? (a) : (b)) + +void SmushReader::processCache(bool sync) { + if (_cacheOp) { + if (sync || fio.poll(_fd)) { // has the transfer finished or were we told to wait for it to finish? + int rdRes = fio.sync(_fd); + assert(rdRes >= 0); + _bytesInCache += rdRes; + _cacheOp = false; + } + } else if (!sync) { + if (_cacheFilePos + _bytesInCache == _fileSize) + return; + + uint32 rdPos = MIN(_lastRead[0], _lastRead[1]); + + int cacheOfs = (rdPos - _cacheFilePos) & ~0xF; // we'd like to keep the buffer aligned to 16 bytes + if (cacheOfs < 0) { + sioprintf("ERROR: smush cache too far ahead!"); + return; + } + + if (_bytesInCache - cacheOfs < SMUSH_CACHE_SIZE - READ_STEP) { + // we want to do some more reading + if (_bytesInCache > cacheOfs) { + _bytesInCache -= cacheOfs; + _cacheBufOfs += cacheOfs; + _cacheFilePos += cacheOfs; + } else { + sioprintf("cache underrun!"); + _bytesInCache = 0; + _cacheBufOfs = 0; + _cacheFilePos = rdPos; + } + + uint32 bufEndPos = (_cacheBufOfs + _bytesInCache) % SMUSH_CACHE_SIZE; + uint32 readLen = SMUSH_CACHE_SIZE - bufEndPos; + if (readLen > READ_STEP) + readLen = READ_STEP; + + fio.read(_fd, _cacheBuf + bufEndPos, readLen); + _cacheOp = true; + } + } +} + +uint32 SmushReader::read(void *dest, uint32 from, uint32 len) { + uint8 *destBuf = (uint8*)dest; + WaitSema(_sema); + if ((from >= _cacheFilePos) && (from + len <= _cacheFilePos + _bytesInCache)) + processCache(false); + else { + processCache(true); // we'll have to read, sync cache before. + } + uint32 readEnds = from + len; + if (from == _lastRead[0]) + _lastRead[0] += len; + else if (from == _lastRead[1]) + _lastRead[1] += len; + else { + if ((_lastRead[0] > readEnds) && (_lastRead[1] < readEnds)) { + _lastRead[1] = readEnds; + } else if ((_lastRead[0] < readEnds) && (_lastRead[1] > readEnds)) { + _lastRead[0] = readEnds; + } else { + if ((_lastRead[0] < readEnds) && (_lastRead[1] < readEnds)) { + if (_lastRead[0] < _lastRead[1]) + _lastRead[0] = readEnds; + else + _lastRead[1] = readEnds; + } else + sioprintf("unexpected readend: %d / %d => %d", _lastRead[0], _lastRead[1], readEnds); + } + } + + while (len) { + while (len && (from >= _cacheFilePos) && (from < _cacheFilePos + _bytesInCache)) { + uint32 cpyOfs = ((from - _cacheFilePos) + _cacheBufOfs) % SMUSH_CACHE_SIZE; + uint32 cpyLen = _bytesInCache - (from - _cacheFilePos); + if (cpyLen > len) + cpyLen = len; + if (cpyOfs + cpyLen > SMUSH_CACHE_SIZE) + cpyLen = SMUSH_CACHE_SIZE - cpyOfs; + memcpy(destBuf, _cacheBuf + cpyOfs, cpyLen); + destBuf += cpyLen; + from += cpyLen; + len -= cpyLen; + } + if (len) { + sioprintf("Smush cache missed: read %d -> %d, cache %d -> %d", from, len, _cacheFilePos, _bytesInCache); + assert(fio.seek(_fd, 0, SEEK_CUR) == _cacheFilePos + _bytesInCache); + fio.seek(_fd, from, SEEK_SET); + int rdRes; + do { + fio.read(_fd, destBuf, len); + rdRes = fio.sync(_fd); + destBuf += rdRes; + from += rdRes; + len -= rdRes; + } while (len && rdRes); + fio.seek(_fd, _cacheFilePos + _bytesInCache, SEEK_SET); + break; + } + } + processCache(false); + SignalSema(_sema); + return destBuf - (uint8*)dest; +} + +void SmushReader::virtSeek(uint32 from, uint32 to) { + WaitSema(_sema); + if (_lastRead[0] == from) + _lastRead[0] = to; + else if (_lastRead[1] == from) + _lastRead[1] = to; + SignalSema(_sema); +} + +uint32 SmushReader::size(void) { + assert(_fd >= 0); + return _fileSize; +} + +bool SmushReader::keepOpened(void) { + return _refCount > 0; +} + +#define MAX_READERS 3 + +static SmushReader *g_smushReaders[MAX_READERS] = { NULL, NULL, NULL }; + +static int g_openSema = -1; + +Ps2SmushFile::Ps2SmushFile(int64 cacheId) : Ps2File(cacheId) { + _filePos = _fileSize = 0; + _id = -1; + if (g_openSema < 0) { + ee_sema_t newSema; + newSema.init_count = 1; + newSema.max_count = 1; + g_openSema = CreateSema(&newSema); + assert(g_openSema >= 0); + } +} + +Ps2SmushFile::~Ps2SmushFile(void) { + WaitSema(g_openSema); + if (_id >= 0) { + g_smushReaders[_id]->close(); + if (!g_smushReaders[_id]->keepOpened()) { + delete g_smushReaders[_id]; + g_smushReaders[_id] = NULL; + } + } + SignalSema(g_openSema); +} + +bool Ps2SmushFile::open(const char *name) { + WaitSema(g_openSema); + int opSlot = MAX_READERS; + for (int i = 0; i < MAX_READERS; i++) { + if (g_smushReaders[i]) { + sioprintf("attaching to reader in slot %d", i); + if (g_smushReaders[i]->open(name) == 0) { + _id = i; + _fileSize = g_smushReaders[i]->size(); + sioprintf("attach ok"); + break; + } + } else if (opSlot == MAX_READERS) + opSlot = i; + } + if (_id < 0) { // smush file wasn't opened before + sioprintf("creating new reader in slot %d", opSlot); + if (opSlot < MAX_READERS) { + g_smushReaders[opSlot] = new SmushReader(); + if (g_smushReaders[opSlot]->open(name) == 0) { + _id = opSlot; + _fileSize = g_smushReaders[opSlot]->size(); + } else { + // can't open file + delete g_smushReaders[opSlot]; + g_smushReaders[opSlot] = NULL; + } + } else + printf("Ran out of reader slots\n"); + } + SignalSema(g_openSema); + return (_id >= 0); +} + +uint32 Ps2SmushFile::read(void *dest, uint32 len) { + int res = g_smushReaders[_id]->read(dest, _filePos, len); + _filePos += res; + return res; +} + +uint32 Ps2SmushFile::write(const void *src, uint32 len) { + printf("ERROR: Received write request on Smush reader\n"); + SleepThread(); + return 0; +} + +uint32 Ps2SmushFile::tell(void) { + return _filePos; +} + +uint32 Ps2SmushFile::size(void) { + return _fileSize; +} + +int Ps2SmushFile::seek(int32 offset, int origin) { + int32 res; + switch (origin) { + case SEEK_SET: + res = offset; + break; + case SEEK_CUR: + res = _filePos + offset; + break; + case SEEK_END: + res = _fileSize + offset; + break; + default: + return -1; + } + if ((res >= 0) && (res <= _fileSize)) { + if (offset != 0) + g_smushReaders[_id]->virtSeek(_filePos, res); + _filePos = res; + return 0; + } + return -1; +} + +bool Ps2SmushFile::eof(void) { + return _filePos == _fileSize; +} + diff --git a/backends/ps2/sysdefs.h b/backends/ps2/sysdefs.h index a00230a26e..50502283f4 100644 --- a/backends/ps2/sysdefs.h +++ b/backends/ps2/sysdefs.h @@ -32,14 +32,16 @@ typedef signed int int32; typedef signed long int64; enum Interrupts { + INT_GS = 0, INT_VBLANK_START = 2, + INT_VBLANK_END = 3, INT_TIMER0 = 9 }; // dma 2 registers #define D2_CHCR (*(volatile uint32*)0x1000A000) -#define D2_QWC (*(volatile uint32*)0x1000A020) // D2_SIZE -#define D2_TADR (*(volatile uint32*)0x1000A030) // D2_TAG +#define D2_QWC (*(volatile uint32*)0x1000A020) +#define D2_TADR (*(volatile uint32*)0x1000A030) #define D2_MADR (*(volatile uint32*)0x1000A010) #define D2_ASR1 (*(volatile uint32*)0x1000A050) #define D2_ASR0 (*(volatile uint32*)0x1000A040) diff --git a/backends/ps2/systemps2.cpp b/backends/ps2/systemps2.cpp index 64636baf48..8e30d1f7bc 100644 --- a/backends/ps2/systemps2.cpp +++ b/backends/ps2/systemps2.cpp @@ -28,7 +28,6 @@ #include <loadfile.h> #include <malloc.h> #include <assert.h> -#include <fileio.h> #include <iopcontrol.h> #include <iopheap.h> #include "scummsys.h" @@ -37,7 +36,7 @@ #include "backends/ps2/systemps2.h" #include "backends/ps2/Gs2dScreen.h" #include "backends/ps2/ps2input.h" -#include "sjpcm.h" +#include <sjpcm.h> #include <cdvd_rpc.h> #include "backends/ps2/savefile.h" #include "common/file.h" @@ -45,13 +44,14 @@ #include <libmc.h> #include "backends/ps2/cd.h" #include <sio.h> +#include <fileXio_rpc.h> #define TIMER_STACK_SIZE (1024 * 32) #define SOUND_STACK_SIZE (1024 * 32) #define SMP_PER_BLOCK 800 #define FROM_BCD(a) ((a >> 4) * 10 + (a & 0xF)) - -#define CHECK_STACK_USAGE +#define BUS_CLOCK (150 * 1000 * 1000) // 150 Mhz Bus clock +#define CLK_DIVIS 5859 // the timer IRQ handler gets called (BUS_CLOCK / 256) / CLK_DIVIS times per second (~100 times) #ifdef USE_PS2LINK #define IRX_PREFIX "host:" @@ -61,13 +61,14 @@ #define IRX_SUFFIX ";1" #endif -static volatile int32 g_TimerThreadSema = -1; -static volatile int32 g_SoundThreadSema = -1; +static int g_TimerThreadSema = -1, g_SoundThreadSema = -1; +static int g_MainWaitSema = -1, g_TimerWaitSema = -1; +static volatile int32 g_MainWakeUp = 0, g_TimerWakeUp = 0; static volatile uint64 msecCount = 0; extern void NORETURN CDECL error(const char *s, ...); -static OSystem_PS2 *g_systemPs2 = NULL; +OSystem_PS2 *g_systemPs2 = NULL; void readRtcTime(void); @@ -94,12 +95,9 @@ extern "C" int scummvm_main(int argc, char *argv[]); extern "C" int main(int argc, char *argv[]) { SifInitRpc(0); -#ifdef USE_PS2LINK - fioInit(); -#else // reset the IOP if this is a CD build +#ifndef USE_PS2LINK // reset the IOP if this is a CD build cdvdInit(CDVD_EXIT); cdvdExit(); - fioExit(); SifExitIopHeap(); SifLoadFileExit(); SifExitRpc(); @@ -109,7 +107,6 @@ extern "C" int main(int argc, char *argv[]) { ; sio_puts("IOP synced."); SifInitRpc(0); - fioInit(); SifLoadFileInit(); cdvdInit(CDVD_INIT_NOWAIT); #endif @@ -141,11 +138,26 @@ extern "C" int main(int argc, char *argv[]) { } s32 timerInterruptHandler(s32 cause) { - msecCount += 10; + msecCount += (((uint64)256 * CLK_DIVIS) << 32) / (BUS_CLOCK / 1000); T0_MODE = 0xDC2; // same value as in initialization. iSignalSema(g_SoundThreadSema); iSignalSema(g_TimerThreadSema); + + if (g_MainWakeUp) { + g_MainWakeUp -= 10; + if (g_MainWakeUp <= 0) { + iSignalSema(g_MainWaitSema); + g_MainWakeUp = 0; + } + } + if (g_TimerWakeUp) { + g_TimerWakeUp -= 10; + if (g_TimerWakeUp <= 0) { + iSignalSema(g_TimerWaitSema); + g_TimerWakeUp = 0; + } + } return 0; } @@ -189,7 +201,7 @@ OSystem_PS2::OSystem_PS2(void) { sioprintf("Initializing LibCDVD."); int res = CDVD_Init(); - sioprintf("result = %d\n", res); + sioprintf("result = %d", res); _timerTid = _soundTid = -1; _mouseVisible = false; @@ -197,14 +209,18 @@ OSystem_PS2::OSystem_PS2(void) { sioprintf("reading RTC"); readRtcTime(); - sioprintf("Setting non-blocking fio"); - fioSetBlockMode(FIO_NOWAIT); // asynchronous file i/o + sioprintf("Initializing FXIO"); + if (fileXioInit() < 0) { + sioprintf("Can't init fileXio\n"); + SleepThread(); + } + fileXioSetBlockMode(FXIO_NOWAIT); sioprintf("Starting SavefileManager"); - _saveManager = new Ps2SaveFileManager(NULL, TO_MC, _screen); + _saveManager = new Ps2SaveFileManager(this, _screen); - _soundBuf = (int16*)malloc(SMP_PER_BLOCK * 2 * sizeof(int16)); - _soundBuf2 = (int16*)malloc(SMP_PER_BLOCK * sizeof(int16)); + _soundBufL = (int16*)malloc(SMP_PER_BLOCK * sizeof(int16)); + _soundBufR = (int16*)malloc(SMP_PER_BLOCK * sizeof(int16)); sioprintf("Initializing ps2Input"); _input = new Ps2Input(this, _useMouse, _useKbd); @@ -217,9 +233,6 @@ OSystem_PS2::~OSystem_PS2(void) { } void OSystem_PS2::initTimer(void) { - // this has to be set before the timer interrupt handler gets called - g_systemPs2 = this; - // first setup the two threads that get activated by the timer: // the timerthread and the soundthread ee_sema_t threadSema; @@ -233,9 +246,7 @@ void OSystem_PS2::initTimer(void) { ReferThreadStatus(GetThreadId(), &thisThread); _timerStack = (uint8*)malloc(TIMER_STACK_SIZE); - memset(_timerStack, 0xE7, TIMER_STACK_SIZE); _soundStack = (uint8*)malloc(SOUND_STACK_SIZE); - memset(_soundStack, 0xE7, SOUND_STACK_SIZE); // give timer thread a higher priority than main thread timerThread.initial_priority = thisThread.current_priority - 1; @@ -260,12 +271,19 @@ void OSystem_PS2::initTimer(void) { StartThread(_timerTid, this); StartThread(_soundTid, this); + // these semaphores are used for OSystem::delay() + threadSema.init_count = 0; + threadSema.max_count = 1; + g_MainWaitSema = CreateSema(&threadSema); + g_TimerWaitSema = CreateSema(&threadSema); + assert((g_MainWaitSema >= 0) && (g_TimerWaitSema >= 0)); + // threads done, start the interrupt handler - AddIntcHandler( INT_TIMER0, timerInterruptHandler, 0); // 0=first handler, 9 = cause = timer0 + AddIntcHandler( INT_TIMER0, timerInterruptHandler, 0); // 0=first handler EnableIntc(INT_TIMER0); T0_HOLD = 0; T0_COUNT = 0; - T0_COMP = 5859; // (busclock / 256) / 5859 = ~ 100.0064 + T0_COMP = CLK_DIVIS; // (busclock / 256) / 5859 = ~ 100.0064 T0_MODE = TIMER_MODE( 2, 0, 0, 0, 1, 1, 1, 0, 1, 1); } @@ -274,7 +292,6 @@ void OSystem_PS2::timerThread(void) { WaitSema(g_TimerThreadSema); if (_scummTimerProc) _scummTimerProc(0); - _screen->timerTick(); } } @@ -284,22 +301,59 @@ void OSystem_PS2::soundThread(void) { soundSema.max_count = 1; _soundSema = CreateSema(&soundSema); assert(_soundSema >= 0); + + int bufferedSamples = 0; + int cycles = 0; while (1) { WaitSema(g_SoundThreadSema); + + if (!(cycles & 31)) + bufferedSamples = SjPCM_Buffered(); + else + bufferedSamples -= 480; + cycles++; WaitSema(_soundSema); if (_scummSoundProc) { - while (SjPCM_Buffered() <= 4 * SMP_PER_BLOCK) { - // call sound mixer - _scummSoundProc(_scummSoundParam, (uint8*)_soundBuf, SMP_PER_BLOCK * 2 * sizeof(int16)); - // split data into 2 buffers, L and R - _soundBuf2[0] = _soundBuf[1]; - for (uint32 cnt = 1; cnt < SMP_PER_BLOCK; cnt++) { - _soundBuf[cnt] = _soundBuf[cnt << 1]; - _soundBuf2[cnt] = _soundBuf[(cnt << 1) | 1]; - } + if (bufferedSamples <= 8 * SMP_PER_BLOCK) { + // we have to produce more samples, call sound mixer + // the scratchpad at 0x70000000 is used as temporary soundbuffer + _scummSoundProc(_scummSoundParam, (uint8*)0x70000000, SMP_PER_BLOCK * 2 * sizeof(int16)); + + // demux data into 2 buffers, L and R + __asm__ ( + "move $t2, %1\n\t" // dest buffer right + "move $t3, %0\n\t" // dest buffer left + "lui $t8, 0x7000\n\t" // muxed buffer, fixed at 0x70000000 + "addiu $t9, $0, 100\n\t" // number of loops + "mtsab $0, 2\n\t" // set qword shift = 2 byte + + "loop:\n\t" + " lq $t4, 0($t8)\n\t" // load 8 muxed samples + " lq $t5, 16($t8)\n\t" // load 8 more muxed samples + + " qfsrv $t6, $0, $t4\n\t" // shift right for second + " qfsrv $t7, $0, $t5\n\t" // packing step (right channel) + + " ppach $t4, $t5, $t4\n\t" // combine left channel data + " ppach $t6, $t7, $t6\n\t" // right channel data + + " sq $t4, 0($t3)\n\t" // write back + " sq $t6, 0($t2)\n\t" // + + " addiu $t9, -1\n\t" // decrement loop counter + " addiu $t2, 16\n\t" // increment pointers + " addiu $t3, 16\n\t" + " addiu $t8, 32\n\t" + " bnez $t9, loop\n\t" // loop + : // outputs + : "r"(_soundBufL), "r"(_soundBufR) // inputs + // : "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", "$t9" // destroyed + : "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25" // destroyed + ); // and feed it into the SPU - SjPCM_Enqueue((short int*)_soundBuf, (short int*)_soundBuf2, SMP_PER_BLOCK, 1); + SjPCM_Enqueue((short int*)_soundBufL, (short int*)_soundBufR, SMP_PER_BLOCK, 0); + bufferedSamples += SMP_PER_BLOCK; } } SignalSema(_soundSema); @@ -321,25 +375,27 @@ bool OSystem_PS2::loadModules(void) { sioprintf("Cannot load module: PADMAN (%d)\n", res); else if ((res = SifLoadModule("rom0:LIBSD", 0, NULL)) < 0) sioprintf("Cannot load module: LIBSD (%d)\n", res); +#ifndef USE_PS2LINK + else if ((res = SifLoadModule(IRX_PREFIX "IOMANX.IRX" IRX_SUFFIX, 0, NULL)) < 0) + sioprintf("Cannot load module: IOMANX.IRX (%d)\n", res); +#endif + else if ((res = SifLoadModule(IRX_PREFIX "FILEXIO.IRX" IRX_SUFFIX, 0, NULL)) < 0) + sioprintf("Cannot load module: FILEXIO.IRX (%d)\n", res); else if ((res = SifLoadModule(IRX_PREFIX "CDVD.IRX" IRX_SUFFIX, 0, NULL)) < 0) sioprintf("Cannot load module CDVD.IRX (%d)\n", res); else if ((res = SifLoadModule(IRX_PREFIX "SJPCM.IRX" IRX_SUFFIX, 0, NULL)) < 0) sioprintf("Cannot load module: SJPCM.IRX (%d)\n", res); else { - sioprintf("modules loaded\n"); + sioprintf("modules loaded"); if ((res = SifLoadModule(IRX_PREFIX "USBD.IRX" IRX_SUFFIX, 0, NULL)) < 0) sioprintf("Cannot load module: USBD.IRX (%d)\n", res); -#ifndef USE_PS2LINK - else if ((res = SifLoadModule(IRX_PREFIX "IOMANX.IRX" IRX_SUFFIX, 0, NULL)) < 0) - sioprintf("Cannot load module: IOMANX.IRX (%d)\n", res); -#endif else { if ((res = SifLoadModule(IRX_PREFIX "PS2MOUSE.IRX" IRX_SUFFIX, 0, NULL)) < 0) sioprintf("Cannot load module: PS2MOUSE.IRX (%d)\n", res); else _useMouse = true; - if ((res = SifLoadModule(IRX_PREFIX "PS2KBD.IRX" IRX_SUFFIX, 0, NULL)) < 0) - sioprintf("Cannot load module: PS2KBD.IRX (%d)\n", res); + if ((res = SifLoadModule(IRX_PREFIX "RPCKBD.IRX" IRX_SUFFIX, 0, NULL)) < 0) + sioprintf("Cannot load module: RPCKBD.IRX (%d)\n", res); else _useKbd = true; } @@ -377,9 +433,9 @@ void OSystem_PS2::copyRectToScreen(const byte *buf, int pitch, int x, int y, int buf -= y * pitch; y = 0; } - if (w > x + _width) + if (x + w > _width) w = _width - x; - if (h > y + _height) + if (y + h > _height) h = _height - y; if ((w > 0) && (h > 0)) _screen->copyScreenRect((const uint8*)buf, (uint16)pitch, (uint16)x, (uint16)y, (uint16)w, (uint16)h); @@ -390,14 +446,25 @@ void OSystem_PS2::updateScreen(void) { } uint32 OSystem_PS2::getMillis(void) { - return (uint32)msecCount; + return (uint32)(msecCount >> 32); } void OSystem_PS2::delayMillis(uint msecs) { - uint64 endTime = msecCount + msecs; + if (msecs == 0) + return; - while (endTime > msecCount) { - // idle + int tid = GetThreadId(); + if (tid == _soundTid) { + sioprintf("ERROR: delayMillis() from sound thread!"); + return; + } + + if (tid == _timerTid) { + g_TimerWakeUp = (int32)msecs; + WaitSema(g_TimerWaitSema); + } else { + g_MainWakeUp = (int32)msecs; + WaitSema(g_MainWaitSema); } } @@ -565,12 +632,12 @@ void OSystem_PS2::quit(void) { static uint32 g_timeSecs; static uint8 g_day, g_month, g_year; -static uint64 g_lastTimeCheck; +static uint32 g_lastTimeCheck; void readRtcTime(void) { struct CdClock cdClock; CDVD_ReadClock(&cdClock); - g_lastTimeCheck = msecCount; + g_lastTimeCheck = (uint32)(msecCount >> 32); if (cdClock.stat) printf("Unable to read RTC time.\n"); @@ -585,7 +652,7 @@ void readRtcTime(void) { g_day, g_month, g_year + 2000); } -time_t time(time_t *p) { +extern time_t time(time_t *p) { time_t blah; memset(&blah, 0, sizeof(time_t)); return blah; @@ -593,11 +660,11 @@ time_t time(time_t *p) { #define SECONDS_PER_DAY (24 * 60 * 60) -struct tm *localtime(const time_t *p) { - uint32 currentSecs = g_timeSecs + (msecCount - g_lastTimeCheck) / 1000; +extern struct tm *localtime(const time_t *p) { + uint32 currentSecs = g_timeSecs + ((msecCount >> 32) - g_lastTimeCheck) / 1000; if (currentSecs >= SECONDS_PER_DAY) { readRtcTime(); - currentSecs = g_timeSecs + (msecCount - g_lastTimeCheck) / 1000; + currentSecs = g_timeSecs + ((msecCount >> 32) - g_lastTimeCheck) / 1000; } static struct tm retStruct; diff --git a/backends/ps2/systemps2.h b/backends/ps2/systemps2.h index 169ffb9088..942cf1b851 100644 --- a/backends/ps2/systemps2.h +++ b/backends/ps2/systemps2.h @@ -93,7 +93,7 @@ private: volatile OSystem::TimerProc _scummTimerProc; volatile OSystem::SoundProc _scummSoundProc; void *_scummSoundParam; - int16 *_soundBuf, *_soundBuf2; + int16 *_soundBufL, *_soundBufR; int _soundSema; void initTimer(void); @@ -107,7 +107,6 @@ private: uint16 _width, _height; Gs2dScreen *_screen; - //PadMouse *_mouse; Ps2Input *_input; uint16 _oldMouseX, _oldMouseY; |