feat: GPU semi-transparency + 85 GTE library seeds + debug commands

GPU fixes:
- Mono tri/quad/rect/dot/8x8/lines: route through sw_renderer with
  semi-transparency support (bit 25 extraction + sw_set_semi_transparency)
- Add 16x16 mono sprite (0x78-0x7B) and 1x1 textured dot (0x6C-0x6F)
- Add per-opcode execution counter (gpu_get_opcode_count)

GTE library: batch-discovered 85 functions in BFC33000-BFC36000
including SetRotMatrix, SetTransMatrix, and full transform pipeline.
Emitted: 1173 (was 1086). Seeds: 955. Zero dispatch misses.

Debug commands: gpu_opcodes, gte_state, screenshot_file (BMP to disk).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matthew Stanley
2026-04-23 14:25:34 -07:00
parent 66c9f21f83
commit 00cc73f20e
5 changed files with 8552 additions and 4407 deletions
+177 -3
View File
@@ -1,7 +1,7 @@
/* AUTO-GENERATED by psxrecomp-bios --emit-full. DO NOT EDIT.
*
* BIOS SHA256: 71af94d1e47a68c11e8fdb9f8368040601514a42a5a399cda48c7d3bff1e99d3
* Dispatch entries: 1087
* Dispatch entries: 1174
*/
#include "cpu_state.h"
@@ -847,15 +847,57 @@ extern void func_1FC33358(CPUState* cpu);
extern void func_1FC33400(CPUState* cpu);
extern void func_1FC33538(CPUState* cpu);
extern void func_1FC336F0(CPUState* cpu);
extern void func_1FC33758(CPUState* cpu);
extern void func_1FC337AC(CPUState* cpu);
extern void func_1FC33800(CPUState* cpu);
extern void func_1FC3388C(CPUState* cpu);
extern void func_1FC33918(CPUState* cpu);
extern void func_1FC33978(CPUState* cpu);
extern void func_1FC339F0(CPUState* cpu);
extern void func_1FC33AB8(CPUState* cpu);
extern void func_1FC33B80(CPUState* cpu);
extern void func_1FC33C04(CPUState* cpu);
extern void func_1FC33C84(CPUState* cpu);
extern void func_1FC33C98(CPUState* cpu);
extern void func_1FC33CC0(CPUState* cpu);
extern void func_1FC33D24(CPUState* cpu);
extern void func_1FC33DA4(CPUState* cpu);
extern void func_1FC33E20(CPUState* cpu);
extern void func_1FC33E80(CPUState* cpu);
extern void func_1FC33E90(CPUState* cpu);
extern void func_1FC33EA0(CPUState* cpu);
extern void func_1FC33EC0(CPUState* cpu);
extern void func_1FC33ECC(CPUState* cpu);
extern void func_1FC33EE0(CPUState* cpu);
extern void func_1FC33EF4(CPUState* cpu);
extern void func_1FC33F00(CPUState* cpu);
extern void func_1FC33F20(CPUState* cpu);
extern void func_1FC33F40(CPUState* cpu);
extern void func_1FC33F54(CPUState* cpu);
extern void func_1FC33F6C(CPUState* cpu);
extern void func_1FC33F80(CPUState* cpu);
extern void func_1FC33F94(CPUState* cpu);
extern void func_1FC33FA8(CPUState* cpu);
extern void func_1FC33FB4(CPUState* cpu);
extern void func_1FC33FCC(CPUState* cpu);
extern void func_1FC33FD8(CPUState* cpu);
extern void func_1FC33FE4(CPUState* cpu);
extern void func_1FC33FF0(CPUState* cpu);
extern void func_1FC33FFC(CPUState* cpu);
extern void func_1FC34008(CPUState* cpu);
extern void func_1FC3401C(CPUState* cpu);
extern void func_1FC34028(CPUState* cpu);
extern void func_1FC3403C(CPUState* cpu);
extern void func_1FC34054(CPUState* cpu);
extern void func_1FC34068(CPUState* cpu);
extern void func_1FC3407C(CPUState* cpu);
extern void func_1FC34088(CPUState* cpu);
extern void func_1FC3409C(CPUState* cpu);
extern void func_1FC340CC(CPUState* cpu);
extern void func_1FC340D8(CPUState* cpu);
extern void func_1FC340E4(CPUState* cpu);
extern void func_1FC34104(CPUState* cpu);
extern void func_1FC34110(CPUState* cpu);
extern void func_1FC34160(CPUState* cpu);
extern void func_1FC34304(CPUState* cpu);
extern void func_1FC344A4(CPUState* cpu);
@@ -863,15 +905,60 @@ extern void func_1FC345F4(CPUState* cpu);
extern void func_1FC34748(CPUState* cpu);
extern void func_1FC34898(CPUState* cpu);
extern void func_1FC348FC(CPUState* cpu);
extern void func_1FC34924(CPUState* cpu);
extern void func_1FC34928(CPUState* cpu);
extern void func_1FC34954(CPUState* cpu);
extern void func_1FC34958(CPUState* cpu);
extern void func_1FC34980(CPUState* cpu);
extern void func_1FC34984(CPUState* cpu);
extern void func_1FC349B8(CPUState* cpu);
extern void func_1FC34A04(CPUState* cpu);
extern void func_1FC34A08(CPUState* cpu);
extern void func_1FC34A30(CPUState* cpu);
extern void func_1FC34A34(CPUState* cpu);
extern void func_1FC34A60(CPUState* cpu);
extern void func_1FC34A64(CPUState* cpu);
extern void func_1FC34A90(CPUState* cpu);
extern void func_1FC34AA0(CPUState* cpu);
extern void func_1FC34AF0(CPUState* cpu);
extern void func_1FC34B08(CPUState* cpu);
extern void func_1FC34B58(CPUState* cpu);
extern void func_1FC34EC0(CPUState* cpu);
extern void func_1FC34EC4(CPUState* cpu);
extern void func_1FC35128(CPUState* cpu);
extern void func_1FC3524C(CPUState* cpu);
extern void func_1FC35348(CPUState* cpu);
extern void func_1FC35470(CPUState* cpu);
extern void func_1FC35598(CPUState* cpu);
extern void func_1FC35698(CPUState* cpu);
extern void func_1FC357C4(CPUState* cpu);
extern void func_1FC3582C(CPUState* cpu);
extern void func_1FC3586C(CPUState* cpu);
extern void func_1FC35890(CPUState* cpu);
extern void func_1FC359B4(CPUState* cpu);
extern void func_1FC35AD8(CPUState* cpu);
extern void func_1FC35B08(CPUState* cpu);
extern void func_1FC35B38(CPUState* cpu);
extern void func_1FC35B68(CPUState* cpu);
extern void func_1FC35B88(CPUState* cpu);
extern void func_1FC35BC4(CPUState* cpu);
extern void func_1FC35C28(CPUState* cpu);
extern void func_1FC35C60(CPUState* cpu);
extern void func_1FC35CC8(CPUState* cpu);
extern void func_1FC35D10(CPUState* cpu);
extern void func_1FC35D58(CPUState* cpu);
extern void func_1FC35DA0(CPUState* cpu);
extern void func_1FC35DD4(CPUState* cpu);
extern void func_1FC35E30(CPUState* cpu);
extern void func_1FC35E64(CPUState* cpu);
extern void func_1FC35E98(CPUState* cpu);
extern void func_1FC35EC0(CPUState* cpu);
extern void func_1FC35EEC(CPUState* cpu);
extern void func_1FC35F18(CPUState* cpu);
extern void func_1FC35F38(CPUState* cpu);
extern void func_1FC35F78(CPUState* cpu);
extern void func_1FC35FA0(CPUState* cpu);
extern void func_1FC35FD0(CPUState* cpu);
extern void func_1FC36068(CPUState* cpu);
extern void func_1FC362D0(CPUState* cpu);
extern void func_1FC36740(CPUState* cpu);
@@ -1113,7 +1200,7 @@ typedef struct {
PsxRecompFunc func;
} DispatchEntry;
static const DispatchEntry dispatch_table[1087] = {
static const DispatchEntry dispatch_table[1174] = {
{ 0x00000500u, func_00000500 },
{ 0x00000510u, func_00000510 },
{ 0x00000520u, func_00000520 },
@@ -1943,15 +2030,57 @@ static const DispatchEntry dispatch_table[1087] = {
{ 0x1FC33400u, func_1FC33400 },
{ 0x1FC33538u, func_1FC33538 },
{ 0x1FC336F0u, func_1FC336F0 },
{ 0x1FC33758u, func_1FC33758 },
{ 0x1FC337ACu, func_1FC337AC },
{ 0x1FC33800u, func_1FC33800 },
{ 0x1FC3388Cu, func_1FC3388C },
{ 0x1FC33918u, func_1FC33918 },
{ 0x1FC33978u, func_1FC33978 },
{ 0x1FC339F0u, func_1FC339F0 },
{ 0x1FC33AB8u, func_1FC33AB8 },
{ 0x1FC33B80u, func_1FC33B80 },
{ 0x1FC33C04u, func_1FC33C04 },
{ 0x1FC33C84u, func_1FC33C84 },
{ 0x1FC33C98u, func_1FC33C98 },
{ 0x1FC33CC0u, func_1FC33CC0 },
{ 0x1FC33D24u, func_1FC33D24 },
{ 0x1FC33DA4u, func_1FC33DA4 },
{ 0x1FC33E20u, func_1FC33E20 },
{ 0x1FC33E80u, func_1FC33E80 },
{ 0x1FC33E90u, func_1FC33E90 },
{ 0x1FC33EA0u, func_1FC33EA0 },
{ 0x1FC33EC0u, func_1FC33EC0 },
{ 0x1FC33ECCu, func_1FC33ECC },
{ 0x1FC33EE0u, func_1FC33EE0 },
{ 0x1FC33EF4u, func_1FC33EF4 },
{ 0x1FC33F00u, func_1FC33F00 },
{ 0x1FC33F20u, func_1FC33F20 },
{ 0x1FC33F40u, func_1FC33F40 },
{ 0x1FC33F54u, func_1FC33F54 },
{ 0x1FC33F6Cu, func_1FC33F6C },
{ 0x1FC33F80u, func_1FC33F80 },
{ 0x1FC33F94u, func_1FC33F94 },
{ 0x1FC33FA8u, func_1FC33FA8 },
{ 0x1FC33FB4u, func_1FC33FB4 },
{ 0x1FC33FCCu, func_1FC33FCC },
{ 0x1FC33FD8u, func_1FC33FD8 },
{ 0x1FC33FE4u, func_1FC33FE4 },
{ 0x1FC33FF0u, func_1FC33FF0 },
{ 0x1FC33FFCu, func_1FC33FFC },
{ 0x1FC34008u, func_1FC34008 },
{ 0x1FC3401Cu, func_1FC3401C },
{ 0x1FC34028u, func_1FC34028 },
{ 0x1FC3403Cu, func_1FC3403C },
{ 0x1FC34054u, func_1FC34054 },
{ 0x1FC34068u, func_1FC34068 },
{ 0x1FC3407Cu, func_1FC3407C },
{ 0x1FC34088u, func_1FC34088 },
{ 0x1FC3409Cu, func_1FC3409C },
{ 0x1FC340CCu, func_1FC340CC },
{ 0x1FC340D8u, func_1FC340D8 },
{ 0x1FC340E4u, func_1FC340E4 },
{ 0x1FC34104u, func_1FC34104 },
{ 0x1FC34110u, func_1FC34110 },
{ 0x1FC34160u, func_1FC34160 },
{ 0x1FC34304u, func_1FC34304 },
{ 0x1FC344A4u, func_1FC344A4 },
@@ -1959,15 +2088,60 @@ static const DispatchEntry dispatch_table[1087] = {
{ 0x1FC34748u, func_1FC34748 },
{ 0x1FC34898u, func_1FC34898 },
{ 0x1FC348FCu, func_1FC348FC },
{ 0x1FC34924u, func_1FC34924 },
{ 0x1FC34928u, func_1FC34928 },
{ 0x1FC34954u, func_1FC34954 },
{ 0x1FC34958u, func_1FC34958 },
{ 0x1FC34980u, func_1FC34980 },
{ 0x1FC34984u, func_1FC34984 },
{ 0x1FC349B8u, func_1FC349B8 },
{ 0x1FC34A04u, func_1FC34A04 },
{ 0x1FC34A08u, func_1FC34A08 },
{ 0x1FC34A30u, func_1FC34A30 },
{ 0x1FC34A34u, func_1FC34A34 },
{ 0x1FC34A60u, func_1FC34A60 },
{ 0x1FC34A64u, func_1FC34A64 },
{ 0x1FC34A90u, func_1FC34A90 },
{ 0x1FC34AA0u, func_1FC34AA0 },
{ 0x1FC34AF0u, func_1FC34AF0 },
{ 0x1FC34B08u, func_1FC34B08 },
{ 0x1FC34B58u, func_1FC34B58 },
{ 0x1FC34EC0u, func_1FC34EC0 },
{ 0x1FC34EC4u, func_1FC34EC4 },
{ 0x1FC35128u, func_1FC35128 },
{ 0x1FC3524Cu, func_1FC3524C },
{ 0x1FC35348u, func_1FC35348 },
{ 0x1FC35470u, func_1FC35470 },
{ 0x1FC35598u, func_1FC35598 },
{ 0x1FC35698u, func_1FC35698 },
{ 0x1FC357C4u, func_1FC357C4 },
{ 0x1FC3582Cu, func_1FC3582C },
{ 0x1FC3586Cu, func_1FC3586C },
{ 0x1FC35890u, func_1FC35890 },
{ 0x1FC359B4u, func_1FC359B4 },
{ 0x1FC35AD8u, func_1FC35AD8 },
{ 0x1FC35B08u, func_1FC35B08 },
{ 0x1FC35B38u, func_1FC35B38 },
{ 0x1FC35B68u, func_1FC35B68 },
{ 0x1FC35B88u, func_1FC35B88 },
{ 0x1FC35BC4u, func_1FC35BC4 },
{ 0x1FC35C28u, func_1FC35C28 },
{ 0x1FC35C60u, func_1FC35C60 },
{ 0x1FC35CC8u, func_1FC35CC8 },
{ 0x1FC35D10u, func_1FC35D10 },
{ 0x1FC35D58u, func_1FC35D58 },
{ 0x1FC35DA0u, func_1FC35DA0 },
{ 0x1FC35DD4u, func_1FC35DD4 },
{ 0x1FC35E30u, func_1FC35E30 },
{ 0x1FC35E64u, func_1FC35E64 },
{ 0x1FC35E98u, func_1FC35E98 },
{ 0x1FC35EC0u, func_1FC35EC0 },
{ 0x1FC35EECu, func_1FC35EEC },
{ 0x1FC35F18u, func_1FC35F18 },
{ 0x1FC35F38u, func_1FC35F38 },
{ 0x1FC35F78u, func_1FC35F78 },
{ 0x1FC35FA0u, func_1FC35FA0 },
{ 0x1FC35FD0u, func_1FC35FD0 },
{ 0x1FC36068u, func_1FC36068 },
{ 0x1FC362D0u, func_1FC362D0 },
{ 0x1FC36740u, func_1FC36740 },
@@ -2221,7 +2395,7 @@ void psx_dispatch(CPUState* cpu, uint32_t addr) {
for (;;) {
cpu->pc = 0;
uint32_t phys = normalize(addr);
int lo = 0, hi = 1087 - 1;
int lo = 0, hi = 1174 - 1;
int found = 0;
while (lo <= hi) {
int mid = (lo + hi) / 2;
+3487 -13
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+43
View File
@@ -444,6 +444,47 @@ static void handle_irq_state(int id, const char *json)
dma_get_dpcr(), dma_get_dicr());
}
/* GPU opcode counter — defined in gpu.c */
extern uint32_t gpu_get_opcode_count(uint8_t op);
static void handle_gpu_opcodes(int id, const char *json)
{
(void)json;
/* Report non-zero GP0 opcode counts */
char buf[4096];
int pos = snprintf(buf, sizeof(buf), "{\"id\":%d,\"ok\":true,\"opcodes\":{", id);
int first = 1;
for (int i = 0; i < 256; i++) {
uint32_t cnt = gpu_get_opcode_count((uint8_t)i);
if (cnt > 0) {
pos += snprintf(buf + pos, sizeof(buf) - pos, "%s\"0x%02X\":%u",
first ? "" : ",", i, cnt);
first = 0;
}
}
pos += snprintf(buf + pos, sizeof(buf) - pos, "}}");
send_fmt("%s", buf);
}
static void handle_gte_state(int id, const char *json)
{
(void)json;
if (!s_cpu) { send_err(id, "no cpu"); return; }
char buf[2048];
int pos = snprintf(buf, sizeof(buf), "{\"id\":%d,\"ok\":true,\"gte_ctrl\":[", id);
for (int i = 0; i < 32; i++) {
pos += snprintf(buf + pos, sizeof(buf) - pos, "%s\"0x%08X\"",
i ? "," : "", s_cpu->gte_ctrl[i]);
}
pos += snprintf(buf + pos, sizeof(buf) - pos, "],\"gte_data\":[");
for (int i = 0; i < 32; i++) {
pos += snprintf(buf + pos, sizeof(buf) - pos, "%s\"0x%08X\"",
i ? "," : "", s_cpu->gte_data[i]);
}
pos += snprintf(buf + pos, sizeof(buf) - pos, "]}");
send_fmt("%s", buf);
}
static void handle_sio_state(int id, const char *json)
{
(void)json;
@@ -1254,6 +1295,8 @@ static const CmdEntry s_commands[] = {
{ "get_snapshots", handle_get_snapshots },
{ "screenshot", handle_screenshot },
{ "screenshot_file", handle_screenshot_file },
{ "gpu_opcodes", handle_gpu_opcodes },
{ "gte_state", handle_gte_state },
{ "quit", handle_quit },
{ "dispatch_check", handle_dispatch_check },
{ "dispatch_tail", handle_dispatch_tail },
+57 -38
View File
@@ -440,6 +440,7 @@ static void raster_triangle(int32_t x0, int32_t y0,
/* Execute mono triangle (GP0 0x20-0x23) */
static void gp0_exec_mono_tri(void) {
int semi_trans = (gp0_cmd_buf[0] >> 25) & 1;
uint16_t color = rgb888_to_rgb555(gp0_cmd_buf[0] & 0xFFFFFFu);
int32_t vx[3], vy[3];
for (int i = 0; i < 3; i++) {
@@ -447,11 +448,13 @@ static void gp0_exec_mono_tri(void) {
vx[i] += draw_offset_x;
vy[i] += draw_offset_y;
}
raster_triangle(vx[0], vy[0], vx[1], vy[1], vx[2], vy[2], color);
sw_set_semi_transparency(semi_trans, (int)semi_transparency);
sw_draw_flat_triangle(vx[0], vy[0], vx[1], vy[1], vx[2], vy[2], color);
}
/* Execute mono quad (GP0 0x28-0x2B) — two triangles: (0,1,2) and (2,1,3) */
static void gp0_exec_mono_quad(void) {
int semi_trans = (gp0_cmd_buf[0] >> 25) & 1;
uint16_t color = rgb888_to_rgb555(gp0_cmd_buf[0] & 0xFFFFFFu);
int32_t vx[4], vy[4];
for (int i = 0; i < 4; i++) {
@@ -459,8 +462,9 @@ static void gp0_exec_mono_quad(void) {
vx[i] += draw_offset_x;
vy[i] += draw_offset_y;
}
raster_triangle(vx[0], vy[0], vx[1], vy[1], vx[2], vy[2], color);
raster_triangle(vx[2], vy[2], vx[1], vy[1], vx[3], vy[3], color);
sw_set_semi_transparency(semi_trans, (int)semi_transparency);
sw_draw_flat_triangle(vx[0], vy[0], vx[1], vy[1], vx[2], vy[2], color);
sw_draw_flat_triangle(vx[2], vy[2], vx[1], vy[1], vx[3], vy[3], color);
}
/* Execute shaded triangle (GP0 0x30-0x33) — Gouraud shaded */
@@ -656,29 +660,20 @@ static void gp0_exec_shaded_textured_quad(void) {
/* Execute mono line (GP0 0x40-0x47) — Bresenham */
static void gp0_exec_mono_line(void) {
int semi_trans = (gp0_cmd_buf[0] >> 25) & 1;
uint16_t color = rgb888_to_rgb555(gp0_cmd_buf[0] & 0xFFFFFFu);
int32_t x0, y0, x1, y1;
parse_vertex(gp0_cmd_buf[1], &x0, &y0);
parse_vertex(gp0_cmd_buf[2], &x1, &y1);
x0 += draw_offset_x; y0 += draw_offset_y;
x1 += draw_offset_x; y1 += draw_offset_y;
/* Simple Bresenham */
int32_t dx = x1 - x0, dy = y1 - y0;
int32_t sx = dx > 0 ? 1 : -1, sy = dy > 0 ? 1 : -1;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
int32_t err = dx - dy;
for (;;) {
raster_pixel(x0, y0, color);
if (x0 == x1 && y0 == y1) break;
int32_t e2 = 2 * err;
if (e2 > -dy) { err -= dy; x0 += sx; }
if (e2 < dx) { err += dx; y0 += sy; }
}
sw_set_semi_transparency(semi_trans, (int)semi_transparency);
sw_draw_line(x0, y0, x1, y1, color);
}
/* Execute shaded line (GP0 0x50-0x57) — flat shaded for now */
static void gp0_exec_shaded_line(void) {
int semi_trans = (gp0_cmd_buf[0] >> 25) & 1;
uint16_t color = rgb888_to_rgb555(gp0_cmd_buf[0] & 0xFFFFFFu);
int32_t x0, y0, x1, y1;
parse_vertex(gp0_cmd_buf[1], &x0, &y0);
@@ -686,34 +681,23 @@ static void gp0_exec_shaded_line(void) {
parse_vertex(gp0_cmd_buf[3], &x1, &y1);
x0 += draw_offset_x; y0 += draw_offset_y;
x1 += draw_offset_x; y1 += draw_offset_y;
int32_t dx = x1 - x0, dy = y1 - y0;
int32_t sx = dx > 0 ? 1 : -1, sy = dy > 0 ? 1 : -1;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
int32_t err = dx - dy;
for (;;) {
raster_pixel(x0, y0, color);
if (x0 == x1 && y0 == y1) break;
int32_t e2 = 2 * err;
if (e2 > -dy) { err -= dy; x0 += sx; }
if (e2 < dx) { err += dx; y0 += sy; }
}
sw_set_semi_transparency(semi_trans, (int)semi_transparency);
sw_draw_line(x0, y0, x1, y1, color);
}
/* Execute mono rectangle (GP0 0x60-0x63) */
static void gp0_exec_mono_rect(void) {
int semi_trans = (gp0_cmd_buf[0] >> 25) & 1;
uint16_t color = rgb888_to_rgb555(gp0_cmd_buf[0] & 0xFFFFFFu);
int32_t x0, y0;
parse_vertex(gp0_cmd_buf[1], &x0, &y0);
x0 += draw_offset_x; y0 += draw_offset_y;
uint32_t w = gp0_cmd_buf[2] & 0xFFFFu;
uint32_t h = (gp0_cmd_buf[2] >> 16) & 0xFFFFu;
/* Clamp to PS1 max */
int w = gp0_cmd_buf[2] & 0xFFFFu;
int h = (gp0_cmd_buf[2] >> 16) & 0xFFFFu;
if (w > 1023) w = 1023;
if (h > 511) h = 511;
for (uint32_t dy = 0; dy < h; dy++)
for (uint32_t dx = 0; dx < w; dx++)
raster_pixel(x0 + (int32_t)dx, y0 + (int32_t)dy, color);
sw_set_semi_transparency(semi_trans, (int)semi_transparency);
sw_draw_flat_rect(x0, y0, w, h, color);
}
/* Execute textured rectangle (GP0 0x64-0x67) */
@@ -739,11 +723,13 @@ static void gp0_exec_textured_rect(void) {
/* Execute 1x1 dot (GP0 0x68-0x6B) */
static void gp0_exec_mono_dot(void) {
int semi_trans = (gp0_cmd_buf[0] >> 25) & 1;
uint16_t color = rgb888_to_rgb555(gp0_cmd_buf[0] & 0xFFFFFFu);
int32_t x, y;
parse_vertex(gp0_cmd_buf[1], &x, &y);
x += draw_offset_x; y += draw_offset_y;
raster_pixel(x, y, color);
sw_set_semi_transparency(semi_trans, (int)semi_transparency);
sw_draw_flat_rect(x, y, 1, 1, color);
}
/* Execute 8x8 textured sprite (GP0 0x74-0x77) */
@@ -765,13 +751,13 @@ static void gp0_exec_textured_8x8(void) {
/* Execute 8x8 sprite (GP0 0x70-0x73) */
static void gp0_exec_mono_8x8(void) {
int semi_trans = (gp0_cmd_buf[0] >> 25) & 1;
uint16_t color = rgb888_to_rgb555(gp0_cmd_buf[0] & 0xFFFFFFu);
int32_t x0, y0;
parse_vertex(gp0_cmd_buf[1], &x0, &y0);
x0 += draw_offset_x; y0 += draw_offset_y;
for (int32_t dy = 0; dy < 8; dy++)
for (int32_t dx = 0; dx < 8; dx++)
raster_pixel(x0 + dx, y0 + dy, color);
sw_set_semi_transparency(semi_trans, (int)semi_transparency);
sw_draw_flat_rect(x0, y0, 8, 8, color);
}
/* Execute 16x16 textured sprite (GP0 0x7C-0x7F) */
@@ -1027,9 +1013,15 @@ static int gp0_command_word_count(uint8_t opcode) {
}
}
/* Per-opcode execution counters (exposed via gpu_get_opcode_stats) */
static uint32_t gp0_opcode_count[256];
uint32_t gpu_get_opcode_count(uint8_t op) { return gp0_opcode_count[op]; }
/* Execute a fully-collected GP0 command */
static void gp0_execute_command(void) {
uint8_t opcode = (gp0_cmd_buf[0] >> 24) & 0xFF;
gp0_opcode_count[opcode]++;
/* Categorize for diagnostics */
if (opcode <= 0x01) gp0_nop_count++;
@@ -1118,12 +1110,39 @@ static void gp0_execute_command(void) {
case 0x68: case 0x69: case 0x6A: case 0x6B:
gp0_exec_mono_dot();
break;
case 0x6C: case 0x6D: case 0x6E: case 0x6F: {
/* 1x1 textured dot: cmd, vertex, texcoord+clut (no size word) */
uint32_t color24 = gp0_cmd_buf[0] & 0xFFFFFFu;
int semi_trans = (gp0_cmd_buf[0] >> 25) & 1;
int32_t x0, y0;
parse_vertex(gp0_cmd_buf[1], &x0, &y0);
x0 += draw_offset_x; y0 += draw_offset_y;
int u0 = gp0_cmd_buf[2] & 0xFF;
int v0 = (gp0_cmd_buf[2] >> 8) & 0xFF;
uint16_t clut = (uint16_t)(gp0_cmd_buf[2] >> 16);
uint16_t clut_x = (clut & 0x3F) * 16;
uint16_t clut_y = (clut >> 6) & 0x1FF;
setup_textured_draw(color24, semi_trans);
sw_draw_textured_rect(x0, y0, 1, 1, u0, v0, clut_x, clut_y, current_texpage());
break;
}
case 0x70: case 0x71: case 0x72: case 0x73:
gp0_exec_mono_8x8();
break;
case 0x74: case 0x75: case 0x76: case 0x77:
gp0_exec_textured_8x8();
break;
case 0x78: case 0x79: case 0x7A: case 0x7B: {
/* 16x16 mono sprite */
int semi_trans = (gp0_cmd_buf[0] >> 25) & 1;
uint16_t color = rgb888_to_rgb555(gp0_cmd_buf[0] & 0xFFFFFFu);
int32_t x0, y0;
parse_vertex(gp0_cmd_buf[1], &x0, &y0);
x0 += draw_offset_x; y0 += draw_offset_y;
sw_set_semi_transparency(semi_trans, (int)semi_transparency);
sw_draw_flat_rect(x0, y0, 16, 16, color);
break;
}
case 0x7C: case 0x7D: case 0x7E: case 0x7F:
gp0_exec_textured_16x16();
break;