aboutsummaryrefslogtreecommitdiff
path: root/src/GPU2D.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/GPU2D.cpp')
-rw-r--r--src/GPU2D.cpp130
1 files changed, 95 insertions, 35 deletions
diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp
index e0da772..288ee58 100644
--- a/src/GPU2D.cpp
+++ b/src/GPU2D.cpp
@@ -246,6 +246,11 @@ u8 GPU2D::Read8(u32 addr)
case 0x049: return WinCnt[1];
case 0x04A: return WinCnt[2];
case 0x04B: return WinCnt[3];
+
+ // there are games accidentally trying to read those
+ // those are write-only
+ case 0x04C:
+ case 0x04D: return 0;
}
printf("unknown GPU read8 %08X\n", addr);
@@ -299,10 +304,22 @@ void GPU2D::Write8(u32 addr, u8 val)
switch (addr & 0x00000FFF)
{
- case 0x000: DispCnt = (DispCnt & 0xFFFFFF00) | val; return;
- case 0x001: DispCnt = (DispCnt & 0xFFFF00FF) | (val << 8); return;
- case 0x002: DispCnt = (DispCnt & 0xFF00FFFF) | (val << 16); return;
- case 0x003: DispCnt = (DispCnt & 0x00FFFFFF) | (val << 24); return;
+ case 0x000:
+ DispCnt = (DispCnt & 0xFFFFFF00) | val;
+ if (Num) DispCnt &= 0xC0B1FFF7;
+ return;
+ case 0x001:
+ DispCnt = (DispCnt & 0xFFFF00FF) | (val << 8);
+ if (Num) DispCnt &= 0xC0B1FFF7;
+ return;
+ case 0x002:
+ DispCnt = (DispCnt & 0xFF00FFFF) | (val << 16);
+ if (Num) DispCnt &= 0xC0B1FFF7;
+ return;
+ case 0x003:
+ DispCnt = (DispCnt & 0x00FFFFFF) | (val << 24);
+ if (Num) DispCnt &= 0xC0B1FFF7;
+ return;
case 0x008: BGCnt[0] = (BGCnt[0] & 0xFF00) | val; return;
case 0x009: BGCnt[0] = (BGCnt[0] & 0x00FF) | (val << 8); return;
@@ -381,8 +398,14 @@ void GPU2D::Write16(u32 addr, u16 val)
switch (addr & 0x00000FFF)
{
- case 0x000: DispCnt = (DispCnt & 0xFFFF0000) | val; return;
- case 0x002: DispCnt = (DispCnt & 0x0000FFFF) | (val << 16); return;
+ case 0x000:
+ DispCnt = (DispCnt & 0xFFFF0000) | val;
+ if (Num) DispCnt &= 0xC0B1FFF7;
+ return;
+ case 0x002:
+ DispCnt = (DispCnt & 0x0000FFFF) | (val << 16);
+ if (Num) DispCnt &= 0xC0B1FFF7;
+ return;
case 0x008: BGCnt[0] = val; return;
case 0x00A: BGCnt[1] = val; return;
@@ -514,6 +537,7 @@ void GPU2D::Write32(u32 addr, u32 val)
{
case 0x000:
DispCnt = val;
+ if (Num) DispCnt &= 0xC0B1FFF7;
return;
case 0x028:
@@ -704,10 +728,6 @@ void GPU2D::DrawScanline(u32 line)
// oddly that's not the case for GPU A
if (Num && !Enabled) forceblank = true;
- // forced blank
- // (checkme: are there still things that can run under this mode? likely not)
- if (DispCnt & (1<<7)) forceblank = true;
-
if (forceblank)
{
for (int i = 0; i < 256; i++)
@@ -748,8 +768,10 @@ void GPU2D::DrawScanline(u32 line)
case 1: // regular display
{
- for (int i = 0; i < stride; i+=2)
+ int i = 0;
+ for (; i < (stride & ~1); i+=2)
*(u64*)&dst[i] = *(u64*)&BGOBJLine[i];
+ if (stride & 1) dst[i] = BGOBJLine[i];
}
break;
@@ -1313,12 +1335,6 @@ void GPU2D::DrawScanlineBGMode(u32 line)
void GPU2D::DrawScanlineBGMode6(u32 line)
{
- if (Num)
- {
- printf("GPU2D: MODE6 ON SUB GPU???\n");
- return;
- }
-
for (int i = 3; i >= 0; i--)
{
if ((BGCnt[2] & 0x3) == i)
@@ -1332,8 +1348,36 @@ void GPU2D::DrawScanlineBGMode6(u32 line)
{
if (DispCnt & 0x0100)
{
- if (DispCnt & 0x8)
+ if ((!Num) && (DispCnt & 0x8))
+ DrawBG_3D();
+ }
+ }
+ if ((DispCnt & 0x1000) && NumSprites)
+ InterleaveSprites(0x8000 | (i<<16));
+ }
+}
+
+void GPU2D::DrawScanlineBGMode7(u32 line)
+{
+ // mode 7 only has text-mode BG0 and BG1
+
+ for (int i = 3; i >= 0; i--)
+ {
+ if ((BGCnt[1] & 0x3) == i)
+ {
+ if (DispCnt & 0x0200)
+ {
+ DrawBG_Text(line, 1);
+ }
+ }
+ if ((BGCnt[0] & 0x3) == i)
+ {
+ if (DispCnt & 0x0100)
+ {
+ if ((!Num) && (DispCnt & 0x8))
DrawBG_3D();
+ else
+ DrawBG_Text(line, 0);
}
}
if ((DispCnt & 0x1000) && NumSprites)
@@ -1343,6 +1387,15 @@ void GPU2D::DrawScanlineBGMode6(u32 line)
void GPU2D::DrawScanline_BGOBJ(u32 line)
{
+ // forced blank disables BG/OBJ compositing
+ if (DispCnt & (1<<7))
+ {
+ for (int i = 0; i < 256; i++)
+ BGOBJLine[i] = 0xFF3F3F3F;
+
+ return;
+ }
+
u64 backdrop;
if (Num) backdrop = *(u16*)&GPU::Palette[0x400];
else backdrop = *(u16*)&GPU::Palette[0];
@@ -1364,7 +1417,6 @@ void GPU2D::DrawScanline_BGOBJ(u32 line)
else
memset(WindowMask, 0xFF, 256);
- // TODO: what happens in mode 7? mode 6 on the sub engine?
switch (DispCnt & 0x7)
{
case 0: DrawScanlineBGMode<0>(line); break;
@@ -1374,6 +1426,7 @@ void GPU2D::DrawScanline_BGOBJ(u32 line)
case 4: DrawScanlineBGMode<4>(line); break;
case 5: DrawScanlineBGMode<5>(line); break;
case 6: DrawScanlineBGMode6(line); break;
+ case 7: DrawScanlineBGMode7(line); break;
}
// color special effects
@@ -2035,14 +2088,19 @@ void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
u32 tilesetaddr, tilemapaddr;
u16* pal;
+ // large BG sizes:
+ // 0: 512x1024
+ // 1: 1024x512
+ // 2: 512x256
+ // 3: 512x512
u32 xmask, ymask;
u32 yshift;
switch (bgcnt & 0xC000)
{
case 0x0000: xmask = 0x1FFFF; ymask = 0x3FFFF; yshift = 9; break;
case 0x4000: xmask = 0x3FFFF; ymask = 0x1FFFF; yshift = 10; break;
- case 0x8000: // TODO (most likely the second size bit is just ignored)
- case 0xC000: printf("bad BG size for large BG: %04X\n", bgcnt); return;
+ case 0x8000: xmask = 0x1FFFF; ymask = 0x0FFFF; yshift = 9; break;
+ case 0xC000: xmask = 0x1FFFF; ymask = 0x1FFFF; yshift = 9; break;
}
u32 ofxmask, ofymask;
@@ -2134,21 +2192,19 @@ void GPU2D::DrawSprites(u32 line)
const s32 spritewidth[16] =
{
- 8, 16, 8, 0,
- 16, 32, 8, 0,
- 32, 32, 16, 0,
- 64, 64, 32, 0
+ 8, 16, 8, 8,
+ 16, 32, 8, 8,
+ 32, 32, 16, 8,
+ 64, 64, 32, 8
};
const s32 spriteheight[16] =
{
- 8, 8, 16, 0,
- 16, 8, 32, 0,
- 32, 16, 32, 0,
- 64, 32, 64, 0
+ 8, 8, 16, 8,
+ 16, 8, 32, 8,
+ 32, 16, 32, 8,
+ 64, 32, 64, 8
};
- u32 nsprites = 0;
-
for (int bgnum = 0x0C00; bgnum >= 0x0000; bgnum -= 0x0400)
{
for (int sprnum = 127; sprnum >= 0; sprnum--)
@@ -2287,8 +2343,10 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
{
if (DispCnt & 0x20)
{
- // TODO ("reserved")
- printf("bad reserved mode\n");
+ // 'reserved'
+ // draws nothing
+
+ return;
}
else
{
@@ -2520,8 +2578,10 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
{
if (DispCnt & 0x20)
{
- // TODO ("reserved")
- printf("bad reserved mode\n");
+ // 'reserved'
+ // draws nothing
+
+ return;
}
else
{