From: <m97...@us...> - 2006-11-18 22:06:47
|
Revision: 5889 http://svn.sourceforge.net/openmsx/?rev=5889&view=rev Author: m9710797 Date: 2006-11-18 14:06:47 -0800 (Sat, 18 Nov 2006) Log Message: ----------- fixed [1188517] Dragon Quest II intro logo corrupted (see ChangeLog) [rb mth] Modified Paths: -------------- openmsx/trunk/ChangeLog openmsx/trunk/src/video/SpriteChecker.cc openmsx/trunk/src/video/SpriteChecker.hh openmsx/trunk/src/video/VDP.cc openmsx/trunk/src/video/VDP.hh Modified: openmsx/trunk/ChangeLog =================================================================== --- openmsx/trunk/ChangeLog 2006-11-18 21:33:52 UTC (rev 5888) +++ openmsx/trunk/ChangeLog 2006-11-18 22:06:47 UTC (rev 5889) @@ -1,5 +1,17 @@ $Id$ +2006-11-18 Wouter Vermaelen <wou...@sc...> + * fixed [1188517] Dragon Quest II intro logo corrupted: + - We had this comment in our code + According to TMS9918.pdf 5th [or 9th] sprite detection + is only active when F flag is zero. + but there was a bug in the actual implementation. + Dragon Quest 2 needs this. + - Bug was caused by splitting storage of VDP status register 0 + over VDP and SpriteChecker class. Now S#0 is stored in VDP and + SpriteChecker uses get/set methods to access the sprite related + bits. + 2006-11-16 Wouter Vermaelen <wou...@sc...> * Speedup SDLGL-PP simple scaler: - taking the average of two pixels and multiplying that with a Modified: openmsx/trunk/src/video/SpriteChecker.cc =================================================================== --- openmsx/trunk/src/video/SpriteChecker.cc 2006-11-18 21:33:52 UTC (rev 5888) +++ openmsx/trunk/src/video/SpriteChecker.cc 2006-11-18 22:06:47 UTC (rev 5889) @@ -14,6 +14,7 @@ #include "SpriteChecker.hh" #include "RenderSettings.hh" #include "BooleanSetting.hh" +#include <algorithm> #include <cassert> namespace openmsx { @@ -30,7 +31,7 @@ void SpriteChecker::reset(const EmuTime& time) { - status = 0; + vdp.setSpriteStatus(0); // TODO 0x00 or 0x1F (blueMSX has 0x1F) collisionX = 0; collisionY = 0; @@ -111,8 +112,10 @@ // Five sprites on a line. // According to TMS9918.pdf 5th sprite detection is only // active when F flag is zero. + byte status = vdp.getStatusReg0(); if ((status & 0xC0) == 0) { - status = (status & 0xE0) | 0x40 | sprite; + vdp.setSpriteStatus( + 0x40 | (status & 0x20) | sprite); } if (limitSprites) break; } @@ -124,9 +127,10 @@ sip->colourAttrib = attributePtr[3]; } } + byte status = vdp.getStatusReg0(); if (~status & 0x40) { // No 5th sprite detected, store number of latest sprite processed. - status = (status & 0xE0) | (sprite < 32 ? sprite : 31); + vdp.setSpriteStatus((status & 0x60) | (std::min(sprite, 31))); } // Optimisation: @@ -134,7 +138,7 @@ // that state is stable until it is reset by a status reg read, // so no need to execute the checks. // The visibleSprites array is filled now, so we can bail out. - if (status & 0x20) return visibleIndex; + if (vdp.getStatusReg0() & 0x20) return visibleIndex; /* Model for sprite collision: (or "coincidence" in TMS9918 data sheet) @@ -165,7 +169,7 @@ } if (pattern_i & pattern_j) { // Collision! - status |= 0x20; + vdp.setSpriteStatus(vdp.getStatusReg0() | 0x20); // TODO: Fill in collision coordinates in S#3..S#6. // ...Unless this feature only works in sprite mode 2. return visibleIndex; @@ -216,8 +220,11 @@ // Nine sprites on a line. // According to TMS9918.pdf 5th sprite detection is only // active when F flag is zero. Stuck to this for V9938. + // Dragon Quest 2 needs this + byte status = vdp.getStatusReg0(); if ((status & 0xC0) == 0) { - status = (status & 0xE0) | 0x40 | sprite; + vdp.setSpriteStatus( + 0x40 | (status & 0x20) | sprite); } if (limitSprites) break; } @@ -236,9 +243,10 @@ sip->colourAttrib = colourAttrib; } } + byte status = vdp.getStatusReg0(); if (~status & 0x40) { // No 9th sprite detected, store number of latest sprite processed. - status = (status & 0xE0) | (sprite < 32 ? sprite : 31); + vdp.setSpriteStatus((status & 0x60) | (std::min(sprite, 31))); } // Optimisation: @@ -246,7 +254,7 @@ // that state is stable until it is reset by a status reg read, // so no need to execute the checks. // The visibleSprites array is filled now, so we can bail out. - if (status & 0x20) return visibleIndex; + if (vdp.getStatusReg0() & 0x20) return visibleIndex; /* Model for sprite collision: (or "coincidence" in TMS9918 data sheet) @@ -286,7 +294,7 @@ } if (pattern_i & pattern_j) { // Collision! - status |= 0x20; + vdp.setSpriteStatus(vdp.getStatusReg0() | 0x20); // TODO: Fill in collision coordinates in S#3..S#6. // See page 97 for info. // TODO: I guess the VDP checks for collisions while Modified: openmsx/trunk/src/video/SpriteChecker.hh =================================================================== --- openmsx/trunk/src/video/SpriteChecker.hh 2006-11-18 21:33:52 UTC (rev 5888) +++ openmsx/trunk/src/video/SpriteChecker.hh 2006-11-18 22:06:47 UTC (rev 5889) @@ -15,26 +15,6 @@ class SpriteChecker: public VRAMObserver { -private: - /** Update sprite checking to specified time. - * This includes a VRAM sync. - * @param time The moment in emulated time to update to. - */ - inline void sync(const EmuTime& time) { - if (mode0) return; - // Debug: - // This method is not re-entrant, so check explicitly that it is not - // re-entered. This can disappear once the VDP-internal scheduling - // has become stable. - static bool syncInProgress = false; - assert(!syncInProgress); - syncInProgress += 0; // avoid warning in none assert build (icc) - syncInProgress = true; - vram.sync(time); - checkUntil(time); - syncInProgress = false; - } - public: /** Bitmap of length 32 describing a sprite pattern. * Visible pixels are 1, transparent pixels are 0. @@ -73,23 +53,31 @@ */ void reset(const EmuTime& time); - /** Gets the sprite status (part of S#0). - * Bit 7 (F) is zero; it is not sprite dependant. - * Bit 6 (5S) is set when more than 4 (sprite mode 1) or 8 (sprite - * mode 2) sprites occur on the same line. - * Bit 5 (C) is set when sprites collide. - * Bit 4..0 (5th sprite number) contains the number of the first - * sprite to exceed the limit per line. - * Reading the status resets some of the bits. + /** Update sprite checking to specified time. + * This includes a VRAM sync. + * @param time The moment in emulated time to update to. */ - inline byte readStatus(const EmuTime& time) { - sync(time); - return status; + inline void sync(const EmuTime& time) { + if (mode0) return; + // Debug: + // This method is not re-entrant, so check explicitly that it is not + // re-entered. This can disappear once the VDP-internal scheduling + // has become stable. + static bool syncInProgress = false; + assert(!syncInProgress); + syncInProgress += 0; // avoid warning in none assert build (icc) + syncInProgress = true; + vram.sync(time); + checkUntil(time); + syncInProgress = false; } + + /** Clear status bits triggered by reading of S#0. + */ inline void resetStatus() { // TODO: Used to be 0x5F, but that is contradicted by // TMS9918.pdf. Check on real MSX. - status &= 0x1F; + vdp.setSpriteStatus(vdp.getStatusReg0() & 0x1F); } /** Informs the sprite checker of a VDP display mode change. @@ -403,10 +391,6 @@ */ int currentLine; - /** The sprite contribution to VDP status register 0. - */ - byte status; - /** X coordinate of sprite collision. * 9 bits long -> [0..511]? */ Modified: openmsx/trunk/src/video/VDP.cc =================================================================== --- openmsx/trunk/src/video/VDP.cc 2006-11-18 21:33:52 UTC (rev 5888) +++ openmsx/trunk/src/video/VDP.cc 2006-11-18 22:06:47 UTC (rev 5889) @@ -639,7 +639,8 @@ { switch (reg) { case 0: - return statusReg0 | spriteChecker->readStatus(time); + spriteChecker->sync(time); + return statusReg0; case 1: if (controlRegs[0] & 0x10) { // line int enabled return statusReg1 | irqHorizontal.getState(); Modified: openmsx/trunk/src/video/VDP.hh =================================================================== --- openmsx/trunk/src/video/VDP.hh 2006-11-18 21:33:52 UTC (rev 5888) +++ openmsx/trunk/src/video/VDP.hh 2006-11-18 22:06:47 UTC (rev 5889) @@ -428,6 +428,24 @@ return getLeftSprites() + getHorizontalScrollLow() * 4; } + /** Should only be used by SpriteChecker. Returns the current value + * of status register 0 (both the F-flag and the sprite related bits). + */ + byte getStatusReg0() const { return statusReg0; } + + /** Should only be used by SpriteChecker. Change the sprite related + * bits of status register 0 (leaves the F-flag unchanged). + * Bit 6 (5S) is set when more than 4 (sprite mode 1) or 8 (sprite + * mode 2) sprites occur on the same line. + * Bit 5 (C) is set when sprites collide. + * Bit 4..0 (5th sprite number) contains the number of the first + * sprite to exceed the limit per line. + */ + void setSpriteStatus(byte value) + { + statusReg0 = (statusReg0 & 0x80) | (value & 0x7F); + } + private: /** Time at which the internal VDP display line counter is reset, * expressed in ticks after vsync. @@ -700,8 +718,8 @@ byte controlValueMasks[32]; /** Status register 0. - * All bits except bit 7 is always zero, - * their value can be retrieved from the sprite checker. + * Both the F flag (bit 7) and the sprite related bits (bits 6-0) + * are stored here. */ byte statusReg0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |