diff --git a/Makefile b/Makefile
index 4eda78b..7ef0a7e 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ IMAGES = common \
gpu/texture-overflow \
gpu/mask-bit \
gpu/gp0-e1 \
+ gpu/vram-to-vram-overlap \
gte-fuzz \
spu/test \
spu/stereo \
diff --git a/README.md b/README.md
index dd7c9dc..014ac8d 100644
--- a/README.md
+++ b/README.md
@@ -4,22 +4,23 @@ Collection of PlayStation 1 tests for emulator development and hardware verifica
## Tests
-Name | Description
----------------------|------------
-gpu/bandwidth | Measure GPU/VRAM bandwidth
-gpu/benchmark | Simple GPU test to benchmark rasteriser
-gpu/quad | Semi-transparent polygon commands - for testing fill rules and transparency handling
-gpu/transparency | Draws rectangles with 4 semi-transparent blending modes
-gpu/triangle | Draws Gouroud shaded equilateral triangle
-gpu/lines | Draws lines using different modes - for verifying Bresenham implementation, color blending, polyline handling
-gpu/rectangles | Draws all combinations of Rectangle commands
-gpu/texture-overflow | Draws textured rectangle with UV overflowing VRAM width
-gpu/mask-bit | Check Mask bit behavior during VRAM copy operations
-gpu/gp0-e1 | Check if GP0_E1, GPUSTAT and polygon render uses the same register internally
-gte-fuzz | Executes GTE opcodes with random parameters, can be used to verify against real console
-spu/test | Check SPU behavior (data is lost randomly on 32bit access, ok on 16bit)
-spu/stereo | Play samples on first two voices
-timers | Run Timer0,1,2 using various clock sources and sync modes and time them using busy loops and vblank interrupt
+Name | Description
+-------------------------|------------
+gpu/bandwidth | Measure GPU/VRAM bandwidth
+gpu/benchmark | Simple GPU test to benchmark rasteriser
+gpu/quad | Semi-transparent polygon commands - for testing fill rules and transparency handling
+gpu/transparency | Draws rectangles with 4 semi-transparent blending modes
+gpu/triangle | Draws Gouroud shaded equilateral triangle
+gpu/lines | Draws lines using different modes - for verifying Bresenham implementation, color blending, polyline handling
+gpu/rectangles | Draws all combinations of Rectangle commands
+gpu/texture-overflow | Draws textured rectangle with UV overflowing VRAM width
+gpu/mask-bit | Check Mask bit behavior during VRAM copy operations
+gpu/gp0-e1 | Check if GP0_E1, GPUSTAT and polygon render uses the same register internally
+gpu/vram-to-vram-overlap | Test GP0(80) VRAM-VRAM copy behaviour in overlapping rects
+gte-fuzz | Executes GTE opcodes with random parameters, can be used to verify against real console
+spu/test | Check SPU behavior (data is lost randomly on 32bit access, ok on 16bit)
+spu/stereo | Play samples on first two voices
+timers | Run Timer0,1,2 using various clock sources and sync modes and time them using busy loops and vblank interrupt
Note: Make sure your PS-EXE loaded does set default value for Stack Pointer - these .exes has SP set to 0.
@@ -39,6 +40,7 @@ diffvram | Diff two images and write diff png if image contents aren
+
## Build
diff --git a/common/gpu.c b/common/gpu.c
index 91b3abc..ad8deb5 100644
--- a/common/gpu.c
+++ b/common/gpu.c
@@ -6,7 +6,7 @@ DRAWENV draw;
void setResolution(int w, int h) {
SetDefDispEnv(&disp, 0, 0, w, h);
- SetDefDrawEnv(&draw, 0, 0, w, h);
+ SetDefDrawEnv(&draw, 0, 0, 1024, 512);
PutDispEnv(&disp);
PutDrawEnv(&draw);
@@ -106,3 +106,19 @@ uint32_t vramGet(int x, int y) {
return readGPU();
}
+
+void vramToVramCopy(int srcX, int srcY, int dstX, int dstY, int w, int h)
+{
+ VRAM2VRAM buf = {0};
+ setcode(&buf, 0x80); // VRAM -> VRAM
+ setlen(&buf, 4);
+
+ buf.x0 = srcX;
+ buf.y0 = srcY;
+ buf.x1 = dstX;
+ buf.y1 = dstY;
+ buf.w = w;
+ buf.h = h;
+
+ DrawPrim(&buf);
+}
diff --git a/common/gpu.h b/common/gpu.h
index 69675b8..7867909 100644
--- a/common/gpu.h
+++ b/common/gpu.h
@@ -36,6 +36,7 @@ void writeGP1(uint8_t cmd, uint32_t data);
uint32_t readGPU();
void vramPut(int x, int y, uint16_t pixel);
uint32_t vramGet(int x, int y);
+void vramToVramCopy(int srcX, int srcY, int dstX, int dstY, int w, int h);
#ifdef __cplusplus
}
diff --git a/gpu/vram-to-vram-overlap/Makefile b/gpu/vram-to-vram-overlap/Makefile
new file mode 100644
index 0000000..54e6e19
--- /dev/null
+++ b/gpu/vram-to-vram-overlap/Makefile
@@ -0,0 +1,3 @@
+include ../../common-test.mk
+
+TARGET = vram-to-vram-overlap.elf
\ No newline at end of file
diff --git a/gpu/vram-to-vram-overlap/font.c b/gpu/vram-to-vram-overlap/font.c
new file mode 100644
index 0000000..abf50c0
--- /dev/null
+++ b/gpu/vram-to-vram-overlap/font.c
@@ -0,0 +1,67 @@
+#include
+#include
+#include
+
+const int fontPosX = 960;
+const int fontPosY = 0;
+
+int fontCharX = 0;
+int fontCharY = 0;
+
+// TODO: refactor font handling to use SDK functions
+void FntInit() {
+ FntLoad(fontPosX, fontPosY);
+}
+
+void FntPos(int x, int y) {
+ fontCharX = x;
+ fontCharY = y;
+}
+
+void FntChar(char c) {
+ if (c == '\n') {
+ fontCharX = 0;
+ fontCharY += 8;
+ return;
+ }
+ if (c >= ' ') {
+ DR_TPAGE e;
+ unsigned short texpage = getTPage(/* bits */ 0, /* semi transparency */ 0, fontPosX, fontPosY);
+ setDrawTPage(&e, /* Drawing to display area */ 1, /* dithering */ 1, texpage);
+ DrawPrim(&e);
+
+ if (c >= 96) {
+ c &= ~(1<<5); // To lower
+ }
+ char pos = c - 33;
+ int u = pos%16;
+ int v = pos/16;
+
+ SPRT_8 t;
+ setSprt8(&t);
+ setXY0(&t, fontCharX, fontCharY);
+ setUV0(&t, u*8, v*8);
+ setClut(&t, fontPosX, 32);
+ setRGB0(&t, 255, 255, 255);
+
+ DrawPrim(&t);
+ }
+
+ fontCharX += 8;
+ if (fontCharX > 1024) {
+ fontCharX = 0;
+ fontCharY += 8;
+ }
+}
+
+void FntPrintf(const char* format, ...) {
+ char buffer[256];
+ va_list args;
+ va_start(args, format);
+ vsprintf(buffer, format, args);
+
+ int len = strlen(buffer);
+ for (int i = 0; i
+#include "font.h"
+
+// 24 bit to 15 bit value
+constexpr uint16_t rgb(uint8_t r, uint8_t g, uint8_t b) {
+ uint16_t c = 0;
+ c |= ((r >> 3) & 0x1f);
+ c |= ((g >> 3) & 0x1f) << 5;
+ c |= ((b >> 3) & 0x1f) << 10;
+ return c;
+}
+
+constexpr uint16_t randomColor(int c) {
+ rgb(64+(c*432)%192, 64+(c*127)%192, 64+(c*941)%192);
+}
+
+// Write sizexsize rect to vram
+void writeRect(int dstX, int dstY, int size) {
+ for (int y = 0; y