ultimecia

A ps1 emulator in c
Log | Files | Refs

commit e3ec2d2175f83466b3ab7734c34cd015d8443605
parent 993827f756cfff97e9351a379498e4747986724b
Author: root <root@fif>
Date:   Fri, 26 Jul 2024 19:51:53 +0000

According to the guide we finished the implementation of the gpu..
Until the point that we are able to display the boot logo!!

Diffstat:
M.gitignore | 1+
Mbuild.sh | 2+-
Msrc/gpu.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/gpu.h | 20+++++++++++++++++++-
Msrc/interconnect.c | 3++-
5 files changed, 139 insertions(+), 20 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,4 @@ +*.vscode bin/ a.out test.c diff --git a/build.sh b/build.sh @@ -1 +1 @@ -cc -std=c89 -Wall -Wpedantic -static -Wall -pedantic -g src/*.c -o bin/ultimecia +cc -Wall -Wpedantic -static -Wall -pedantic -g src/*.c -o bin/ultimecia diff --git a/src/gpu.c b/src/gpu.c @@ -47,7 +47,7 @@ GPU_status(GPU* gpu) /* Bit 14 not supported */ r |= ((u32)gpu->texture_disable) << 15; r |= HOR_RES_into_status(gpu->hres); - r |= ((u32)gpu->vres) << 19; + //r |= ((u32)gpu->vres) << 19; r |= ((u32)gpu->vmode) << 20; r |= ((u32)gpu->display_depth) << 21; r |= ((u32)gpu->interlaced) << 22; @@ -82,13 +82,16 @@ void GPU_gp1(GPU* gpu, u32 val) { - u32 opcode, len; + u32 opcode; opcode = (val >> 24) & 0xff; switch (opcode) { case 0x00: GPU_gp1_reset(gpu, val); break; + case 0x01: GPU_gp1_reset_command_buffer(gpu, val); break; + case 0x02: GPU_gp1_acknowledge_irq(gpu, val); break; + case 0x03: GPU_gp1_display_enable(gpu, val); break; case 0x04: GPU_gp1_dma_direction(gpu, val); break; case 0x05: GPU_gp1_display_vram_start(gpu, val); break; case 0x06: GPU_gp1_display_horizontal_range(gpu, val); break; @@ -102,7 +105,7 @@ GPU_gp1(GPU* gpu, u32 val) void GPU_gp1_reset(GPU* gpu, u32 val) { - memset(gpu, 0, sizeof(GPU)); + 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; @@ -113,6 +116,28 @@ GPU_gp1_reset(GPU* gpu, u32 val) } void +GPU_gp1_display_enable(GPU* gpu, u32 val) +{ + gpu->display_disabled = (val & 1) != 0; +} + +void +GPU_gp1_acknowledge_irq(GPU* gpu, u32 val) +{ + gpu->interrupt = 0; +} + +void +GPU_gp1_reset_command_buffer(GPU* gpu, u32 val) +{ + GPU_CMD_BUFFER_clear(&gpu->gp0_command); + gpu->gp0_words_remaining = 0; + gpu->gp0_mode = GP0_MODE_COMMAND; + + // XXX Should also clear the command FIFO when we implement it +} + +void GPU_gp1_display_horizontal_range(GPU* gpu, u32 val) { gpu->display_horiz_start = (u16)(val & 0xfff); @@ -154,10 +179,10 @@ GPU_gp1_display_mode(GPU* gpu, u32 val) 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); + gpu->vres = (val & 0x4) != 0; + gpu->vmode = (val & 0x8) != 0 ? VMODE_NTSC : VMODE_PAL; + gpu->display_depth = (val & 0x10) != 0 ? DISP_DEPTH_D24BITS : DISP_DEPTH_D15BITS; + gpu->interlaced = (val & 0x20) != 0; if (val & 0x80) fprintf(stderr, "Unsupported display mode %08X\n", val), exit(EXIT_FAILURE); @@ -166,7 +191,7 @@ GPU_gp1_display_mode(GPU* gpu, u32 val) void GPU_gp0(GPU* gpu, u32 val) { - if (gpu->gp0_command_remaining == 0) { + if (gpu->gp0_words_remaining == 0) { u32 opcode, len; void (*method)(GPU*); @@ -174,28 +199,60 @@ GPU_gp0(GPU* gpu, u32 val) switch (opcode) { case 0x00: len = 1; method = GPU_gp0_nop; break; + case 0x01: len = 1; method = GPU_gp0_clear_cache; break; + case 0xa0: len = 3; method = GPU_gp0_image_load; break; case 0xe1: len = 1; method = GPU_gp0_draw_mode; break; case 0xe2: len = 1; method = GPU_gp0_texture_window; break; case 0xe3: len = 1; method = GPU_gp0_drawing_area_top_left; break; case 0xe4: len = 1; method = GPU_gp0_drawing_area_bottom_right; break; case 0xe5: len = 1; method = GPU_gp0_drawing_offset; break; case 0xe6: len = 1; method = GPU_gp0_mask_bit_setting; break; + case 0x28: len = 5; method = GPU_gp0_quad_mono_opaque; break; + case 0x2c: len = 9; method = GPU_gp0_quad_texture_blend_opaque; break; + case 0x30: len = 6; method = GPU_gp0_triangle_shaded_opaque; break; + case 0x38: len = 8; method = GPU_gp0_quad_shaded_opaque; break; + case 0xc0: len = 3; method = GPU_gp0_image_store; break; default: fprintf(stderr, "OP: %08X: Unhandled GP0 command %08X\n", opcode, val); exit(1); } - gpu->gp0_command_remaining = len; + gpu->gp0_words_remaining = len; gpu->gp0_command_method = method; GPU_CMD_BUFFER_clear(&gpu->gp0_command); } - GPU_CMD_BUFFER_push_word(&gpu->gp0_command, val); - gpu->gp0_command_remaining -= 1; - if (gpu->gp0_command_remaining == 0) - gpu->gp0_command_method(gpu); + gpu->gp0_words_remaining -= 1; + + switch (gpu->gp0_mode) { + case GP0_MODE_COMMAND: + GPU_CMD_BUFFER_push_word(&gpu->gp0_command, val); + if (gpu->gp0_words_remaining == 0) + gpu->gp0_command_method(gpu); + break; + case GP0_MODE_IMAGE_LOAD: + if (gpu->gp0_words_remaining == 0) + gpu->gp0_mode = GP0_MODE_COMMAND; + break; + } } void GPU_gp0_nop(GPU* gpu) {} +void GPU_gp0_clear_cache(GPU* gpu) { /* Not implemented */} + +void +GPU_gp0_image_load(GPU* gpu) +{ + u32 res, width, height, imgsize; + + res = gpu->gp0_command.buffer[2]; + width = res & 0xffff; + height = res >> 16; + imgsize = width * height; + imgsize = (imgsize + 1) & ~1; + gpu->gp0_words_remaining = imgsize / 2; + gpu->gp0_mode = GP0_MODE_IMAGE_LOAD; +} + void GPU_gp0_draw_mode(GPU* gpu) { @@ -277,8 +334,44 @@ GPU_gp0_mask_bit_setting(GPU* gpu) u32 val; val = gpu->gp0_command.buffer[0]; - gpu->force_set_mask_bit = val & 1; - gpu->preserve_masked_pixels = val & 2; + gpu->force_set_mask_bit = (val & 1) != 0; + gpu->preserve_masked_pixels = (val & 2) != 0; +} + +void +GPU_gp0_quad_mono_opaque(GPU* gpu) +{ + fprintf(stdout, "Draw quad pls\n"); +} + +void +GPU_gp0_triangle_shaded_opaque(GPU* gpu) +{ + fprintf(stdout, "Draw triangle shaded\n"); +} + +void +GPU_gp0_quad_texture_blend_opaque(GPU* gpu) +{ + fprintf(stdout, "Draw quad texture blending\n"); +} + +void +GPU_gp0_quad_shaded_opaque(GPU* gpu) +{ + fprintf(stdout, "Draw quad shaded\n"); +} + +void +GPU_gp0_image_store(GPU* gpu) +{ + u32 res, width, height; + + res = gpu->gp0_command.buffer[2]; + width = res & 0xffff; + height = res >> 16; + + fprintf(stdout, "Unhandled image store: %dx%d\n", width, height); } GPU_CMD_BUFFER* @@ -292,7 +385,12 @@ GPU_CMD_BUFFER_new(void) return buffer; } -void GPU_CMD_BUFFER_clear(GPU_CMD_BUFFER* cmd_buffer) { if (cmd_buffer == NULL) return; cmd_buffer->len = 0; } +void +GPU_CMD_BUFFER_clear(GPU_CMD_BUFFER* cmd_buffer) +{ + cmd_buffer->len = 0; + /*memset(cmd_buffer->buffer, 413, 12 * sizeof(u32));*/ +} void GPU_CMD_BUFFER_push_word(GPU_CMD_BUFFER* cmd_buffer, u32 word) @@ -302,4 +400,4 @@ GPU_CMD_BUFFER_push_word(GPU_CMD_BUFFER* cmd_buffer, u32 word) cmd_buffer->buffer[cmd_buffer->len] = word; cmd_buffer->len++; -} +} +\ No newline at end of file diff --git a/src/gpu.h b/src/gpu.h @@ -2,6 +2,11 @@ #include "types.h" +typedef enum _GP0_MODE { + GP0_MODE_COMMAND, + GP0_MODE_IMAGE_LOAD +} GP0_MODE; + typedef enum _TEXTURE_DEPTH { TD_T4BIT, TD_T8BIT, @@ -76,8 +81,10 @@ typedef struct _GPU { u16 display_line_start; u16 display_line_end; + GP0_MODE gp0_mode; + GPU_CMD_BUFFER gp0_command; - u32 gp0_command_remaining; + u32 gp0_words_remaining; void (*gp0_command_method) (struct _GPU*); } GPU; @@ -87,6 +94,9 @@ 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_reset_command_buffer(GPU*, u32); /* GP1(0x01): Reset Command Buffer */ +void GPU_gp1_acknowledge_irq(GPU*, u32); /* GP1(0x02): Acknoweledge Interrupt */ +void GPU_gp1_display_enable(GPU*, u32); /* GP1(0x03): Display Enable */ void GPU_gp1_dma_direction(GPU*, u32); /* GP1(0x04): DMA Direction */ void GPU_gp1_display_mode(GPU*, u32); /* GP1(0x08): Display Mode */ void GPU_gp1_display_vram_start(GPU*, u32); /* GP1(0x05): Display VRAM start */ @@ -96,13 +106,21 @@ void GPU_gp1_display_vertical_range(GPU*, u32); /* GP1(0x07): Display Vertical R /* GP0 */ void GPU_gp0(GPU*, u32); void GPU_gp0_nop(GPU*); +void GPU_gp0_clear_cache(GPU*); /* GP0(0x01): Clear Cache */ +void GPU_gp0_image_load(GPU*); /* GP0(0xa0): Image Load */ void GPU_gp0_draw_mode(GPU*); void GPU_gp0_drawing_area_top_left(GPU*); /* GP0(0xe3): Set Drawing Area top left */ void GPU_gp0_drawing_area_bottom_right(GPU*); /* GP0(0xe4): Set Drawing Area bottom right */ void GPU_gp0_drawing_offset(GPU*); /* GP0(0xe5): Set Drawing Offset */ void GPU_gp0_texture_window(GPU*); /* GP0(0xe2): Set Texture Window */ void GPU_gp0_mask_bit_setting(GPU*); /* GP0(0xe6): Set Mask Bit Setting */ +void GPU_gp0_quad_mono_opaque(GPU*); /* GP0(0x28): Monochrome Opaque Quadrilateral */ +void GPU_gp0_triangle_shaded_opaque(GPU*); /* GP0(0x30): Shaded Opaque Triangle */ +void GPU_gp0_quad_shaded_opaque(GPU*); /* GP0(0x38): Shaded Opaque Quadrilateral */ +void GPU_gp0_quad_texture_blend_opaque(GPU*); /* GP0(0x2c): Textured Opaque Quadrilateral */ +void GPU_gp0_image_store(GPU*); /* GP0(0xc0): Image store */ GPU* GPU_new(void); +u32 GPU_status(GPU*); u32 GPU_read(GPU*); /* GPU's Command Buffer: GPU_CMD_BUFFER */ diff --git a/src/interconnect.c b/src/interconnect.c @@ -158,7 +158,7 @@ INTER_load32(Interconnect* inter, u32 addr) switch(offset) { case 0: return GPU_read(inter->gpu); /* NOT COMPLETE */ - case 4: return 0x1c000000; + case 4: return GPU_status(inter->gpu); default: return 0; } } @@ -491,6 +491,7 @@ INTER_do_dma_block(Interconnect* inter, Port port) src_word = RAM_load32(inter->ram, cur_addr); switch(port) { case PORT_GPU: + GPU_gp0(inter->gpu, src_word); #ifndef DEBUG printf("GPU data %08X\n", src_word); #endif