ultimecia

A ps1 emulator in c
Log | Files | Refs

commit fa1190dccb02895c82f3b65ea09e28b7a2f2d2d8
parent 734b221f69109ea06644f5430fd2284b497832f5
Author: root <root@fif>
Date:   Sun, 21 Jul 2024 09:59:15 +0000

Progress on the gpu implementation.
Implemented some GP0 and GP1 opcodes

Diffstat:
Msrc/gpu.c | 125++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/gpu.h | 28++++++++++++++++++++++++++++
Msrc/interconnect.c | 16+++++++++++-----
Msrc/interconnect.h | 2++
Msrc/main.c | 1-
5 files changed, 162 insertions(+), 10 deletions(-)

diff --git a/src/gpu.c b/src/gpu.c @@ -21,6 +21,12 @@ GPU_new(void) } u32 +GPU_read(GPU* gpu) +{ + return 0; +} + +u32 GPU_status(GPU* gpu) { u32 r; @@ -73,7 +79,7 @@ GPU_status(GPU* gpu) } void -GPU_gp0(GPU* gpu, u32 val) +GPU_gp1(GPU* gpu, u32 val) { u32 opcode; @@ -82,13 +88,76 @@ GPU_gp0(GPU* gpu, u32 val) switch (opcode) { - case 0xe1: GPU_gp0_draw_mode(gpu, val); break; - default: fprintf(stderr, "Unhandled GP0 command %08X\n", val); exit(1); + case 0x00: GPU_gp1_reset(gpu, val); break; + case 0x04: GPU_gp1_dma_direction(gpu, val); break; + case 0x08: GPU_gp1_display_mode(gpu, val); break; + default: fprintf(stderr, "OP: %08X: Unhandled GP1 command %08X\n", opcode, val); exit(1); } } -/* TOBECONTINUED */ +void +GPU_gp1_reset(GPU* gpu, u32 val) +{ + memset(gpu, 0, sizeof(GPU)); + /* Fill out the rest of the fields with no$cash spec reset values*/ + gpu->display_disabled = 1; + gpu->interlaced = 1; + gpu->display_horiz_start = 0x200; + gpu->display_horiz_end = 0xc00; + gpu->display_line_start = 0x10; + gpu->display_line_end = 0x100; +} + +void +GPU_gp1_dma_direction(GPU* gpu, u32 val) +{ + switch (val & 3) { + case 0: gpu->dma_direction = DMA_DIR_OFF; break; + case 1: gpu->dma_direction = DMA_DIR_FIFO; break; + case 2: gpu->dma_direction = DMA_DIR_CPUTOGP0; break; + case 3: gpu->dma_direction = DMA_DIR_VRAMTOCPU; break; + default: fprintf(stderr, "UNREACHABLE"); exit(EXIT_FAILURE); + } +} + +void +GPU_gp1_display_mode(GPU* gpu, u32 val) +{ + u8 hr1, hr2; + + hr1 = (u8)(val & 3); + hr2 = (u8)((val >> 6) & 1); + + gpu->hres = HOR_RES_from_fields(hr1, hr2); + gpu->vres = (val & 0x4); + gpu->vmode = (val & 0x8) ? VMODE_PAL : VMODE_NTSC; + gpu->display_depth = (val & 0x10) ? DISP_DEPTH_D24BITS : DISP_DEPTH_D15BITS; + gpu->interlaced = (val & 0x20); + + if (val & 0x80) + fprintf(stderr, "Unsupported display mode %08X\n", val), exit(EXIT_FAILURE); +} + +void +GPU_gp0(GPU* gpu, u32 val) +{ + u32 opcode; + + opcode = (val >> 24) & 0xff; + + switch (opcode) { + case 0x00: break; + case 0xe1: GPU_gp0_draw_mode(gpu, val); break; + case 0xe2: GPU_gp0_texture_window(gpu, val); break; + case 0xe3: GPU_gp0_drawing_area_top_left(gpu, val); break; + case 0xe4: GPU_gp0_drawing_area_bottom_right(gpu, val); break; + case 0xe5: GPU_gp0_drawing_offset(gpu, val); break; + case 0xe6: GPU_gp0_mask_bit_setting(gpu, val); break; + default: fprintf(stderr, "OP: %08X: Unhandled GP0 command %08X\n", opcode, val); exit(1); + } +} + void GPU_gp0_draw_mode(GPU* gpu, u32 val) { @@ -107,5 +176,53 @@ GPU_gp0_draw_mode(GPU* gpu, u32 val) default: fprintf(stderr, "Unhandled texture depth %d\n", (val >> 7) & 3); exit(1); } + gpu->dithering = ((val >> 9) & 1); + gpu->draw_to_display = ((val >> 10) & 1); + gpu->texture_disable = ((val >> 11) & 1); + gpu->rectangle_texture_x_flip = ((val >> 12) & 1); + gpu->rectangle_texture_y_flip = ((val >> 13) & 1); +} + +void +GPU_gp0_drawing_area_top_left(GPU* gpu, u32 val) +{ + gpu->drawing_area_top = (u16)((val >> 10) & 0x3ff); + gpu->drawing_area_left = (u16)(val & 0x3ff); +} + +void +GPU_gp0_drawing_area_bottom_right(GPU* gpu, u32 val) +{ + gpu->drawing_area_bottom = (u16)((val >> 10) & 0x3ff); + gpu->drawing_area_right = (u16)(val & 0x3ff); +} + +void +GPU_gp0_drawing_offset(GPU* gpu, u32 val) +{ + u16 x, y; + + x = (u16)(val & 0x7ff); + y = (u16)((val >> 11) & 0x7ff); + + /* Values here are 11bit 2s complement signed values, we need to force sign extension */ + gpu->drawing_x_offset = ((i16)(x << 5)) >> 5; + gpu->drawing_y_offset = ((i16)(y << 5)) >> 5; + } +void +GPU_gp0_texture_window(GPU* gpu, u32 val) +{ + gpu->texture_window_x_mask = (u8)(val & 0x1f); + gpu->texture_window_y_mask = (u8)((val >> 5) & 0x1f); + gpu->texture_window_x_offset = (u8)((val >> 10) & 0x1f); + gpu->texture_window_y_offset = (u8)((val >> 15) & 0x1f); +} + +void +GPU_gp0_mask_bit_setting(GPU* gpu, u32 val) +{ + gpu->force_set_mask_bit = val & 1; + gpu->preserve_masked_pixels = val & 2; +} diff --git a/src/gpu.h b/src/gpu.h @@ -53,10 +53,38 @@ typedef struct _GPU { u8 rectangle_texture_x_flip; u8 rectangle_texture_y_flip; + + u8 texture_window_x_mask; + u8 texture_window_y_mask; + u8 texture_window_x_offset; + u8 texture_window_y_offset; + u16 drawing_area_left; + u16 drawing_area_top; + u16 drawing_area_right; + u16 drawing_area_bottom; + i16 drawing_x_offset; + i16 drawing_y_offset; + u16 display_vram_x_start; + u16 display_vram_y_start; + u16 display_horiz_start; + u16 display_horiz_end; + u16 display_line_start; + u16 display_line_end; + } GPU; u8 HOR_RES_from_fields(u8, u8); u32 HOR_RES_into_status(u8); +void GPU_gp1(GPU*, u32); +void GPU_gp1_reset(GPU*, u32); /* GP1(0x00): Reset */ +void GPU_gp1_dma_direction(GPU*, u32); /* GP1(0x04): DMA Direction */ +void GPU_gp1_display_mode(GPU*, u32); /* GP1(0x08): Display Mode */ void GPU_gp0(GPU*, u32); void GPU_gp0_draw_mode(GPU*, u32); +void GPU_gp0_drawing_area_top_left(GPU*, u32); /* GP0(0xe3): Set Drawing Area top left */ +void GPU_gp0_drawing_area_bottom_right(GPU*, u32); /* GP0(0xe4): Set Drawing Area bottom right */ +void GPU_gp0_drawing_offset(GPU*, u32); /* GP0(0xe5): Set Drawing Offset */ +void GPU_gp0_texture_window(GPU*, u32); /* GP0(0xe2): Set Texture Window */ +void GPU_gp0_mask_bit_setting(GPU*, u32); /* GP0(0xe6): Set Mask Bit Setting */ GPU* GPU_new(void); +u32 GPU_read(GPU*); diff --git a/src/interconnect.c b/src/interconnect.c @@ -7,6 +7,7 @@ #include "util.h" #include "types.h" #include "defs.h" +#include "gpu.h" Interconnect* new_interconnect(void) { @@ -14,6 +15,7 @@ new_interconnect(void) { inter->bios = BIOS_new("roms/scph1001.bin"); inter->ram = RAM_new(); inter->dma = DMA_new(); + inter->gpu = GPU_new(); return inter; } @@ -149,12 +151,11 @@ INTER_load32(Interconnect* inter, u32 addr) contains = UTIL_contains(GPU_START, GPU_SIZE, abs_addr, &offset); if (contains) { -#ifndef DEBUG printf("GPU read %08X\n", abs_addr); -#endif switch(offset) { + case 0: return GPU_read(inter->gpu); /* NOT COMPLETE */ case 4: return 0x1c000000; default: return 0; } @@ -247,7 +248,7 @@ INTER_store16(Interconnect* inter, u32 addr, u16 val) PANIC("Unhandled store16 into abs_address: %08X\n", abs_addr); } - void +void INTER_store32(Interconnect* inter, u32 addr, u32 val) { u32 offset; @@ -317,9 +318,13 @@ INTER_store32(Interconnect* inter, u32 addr, u32 val) contains = UTIL_contains(GPU_START, GPU_SIZE, abs_addr, &offset); if (contains) { -#ifndef DEBUG fprintf(stdout, "GPU write %08X to address %08X\n", val, offset); -#endif + switch (offset) { + case 0: GPU_gp0(inter->gpu, val); break; + case 4: GPU_gp1(inter->gpu, val); break; + default: fprintf(stderr, "GPU write %08X: %08X", offset, val); exit(EXIT_FAILURE); + } + return; } @@ -543,6 +548,7 @@ INTER_do_dma_linked_list(Interconnect* inter, Port port) while (remsz > 0) { addr = (addr + 4) & 0x1ffffc; command = RAM_load32(inter->ram, addr); + GPU_gp0(inter->gpu, command); #ifndef DEBUG printf("GPU command %08X\n", command); #endif diff --git a/src/interconnect.h b/src/interconnect.h @@ -2,12 +2,14 @@ #include "bios.h" #include "mem.h" +#include "gpu.h" #include "types.h" struct Interconnect { BIOS* bios; RAM* ram; DMA* dma; + GPU* gpu; }; typedef struct Interconnect Interconnect; diff --git a/src/main.c b/src/main.c @@ -14,7 +14,6 @@ int main(int argc, char **argv) { CPU* cpu; - GPU* gpu; Interconnect* inter; inter = new_interconnect();