ultimecia

A ps1 emulator in c
Log | Files | Refs

commit 734b221f69109ea06644f5430fd2284b497832f5
parent dd25e590a2a1f91dd5a6ea1023d96546cb0aef74
Author: edea <none@fithos.xyz>
Date:   Sun, 14 Jul 2024 11:26:06 +0300

continuing with GPUSTAT register

Diffstat:
Mbuild.sh | 2+-
Msrc/gpu.c | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/gpu.h | 51++++++++++++++++++++++++++++++++++++++++-----------
Msrc/interconnect.c | 310++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/main.c | 2++
Mtest.cc | 6++++++
6 files changed, 314 insertions(+), 167 deletions(-)

diff --git a/build.sh b/build.sh @@ -1 +1 @@ -c++ -O3 -Wall -Wpedantic -static -Wall -pedantic -g src/*.c -o bin/ultimecia +cc -O3 -Wall -Wpedantic -static -Wall -pedantic -g src/*.c -o bin/ultimecia diff --git a/src/gpu.c b/src/gpu.c @@ -1 +1,111 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "gpu.h" +#include "types.h" +#include "defs.h" + +u8 HOR_RES_from_fields(u8 hr1, u8 hr2) { return (hr2 & 1) | ((hr1 & 3) << 1); } +u32 HOR_RES_into_status(u8 hr) {return ((u32)hr) << 16; } + +GPU* +GPU_new(void) +{ + GPU* gpu; + + gpu = (GPU*)malloc(sizeof(GPU)); + memset(gpu, 0, sizeof(GPU)); + gpu->display_disabled = 1; + + return gpu; +} + +u32 +GPU_status(GPU* gpu) +{ + u32 r; + u32 dma_req; + + dma_req = 0; + r = 0; + + r |= ((u32)gpu->page_base_x) << 0; + r |= ((u32)gpu->page_base_y) << 4; + r |= ((u32)gpu->semi_transparency) << 5; + r |= ((u32)gpu->texture_depth) << 7; + r |= ((u32)gpu->dithering) << 9; + r |= ((u32)gpu->draw_to_display) << 10; + r |= ((u32)gpu->force_set_mask_bit) << 11; + r |= ((u32)gpu->preserve_masked_pixels) << 12; + r |= ((u32)gpu->field) << 13; + /* 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->vmode) << 20; + r |= ((u32)gpu->display_depth) << 21; + r |= ((u32)gpu->interlaced) << 22; + r |= ((u32)gpu->display_disabled) << 23; + r |= ((u32)gpu->interrupt) << 24; + + /* Always GPU is ready */ + r |= 1 << 26; + r |= 1 << 27; + r |= 1 << 28; + + r |= ((u32) gpu->dma_direction) << 29; + + /* Ignore odd lines for now */ + r |= 0 << 31; + + switch(gpu->dma_direction) + { + case DMA_DIR_OFF: dma_req = 0; break; + case DMA_DIR_FIFO: dma_req = 1; break; + case DMA_DIR_CPUTOGP0: dma_req = (r >> 28) & 1; break; + case DMA_DIR_VRAMTOCPU: dma_req = (r >> 27) & 1; break; + default: fprintf(stderr, "UNREACHABLE"); exit(1); + } + + r |= dma_req << 25; + + return r; +} + +void +GPU_gp0(GPU* gpu, u32 val) +{ + + u32 opcode; + + opcode = (val >> 24) & 0xff; + + switch (opcode) + { + case 0xe1: GPU_gp0_draw_mode(gpu, val); break; + default: fprintf(stderr, "Unhandled GP0 command %08X\n", val); exit(1); + } + +} + +/* TOBECONTINUED */ +void +GPU_gp0_draw_mode(GPU* gpu, u32 val) +{ + gpu->page_base_x = (u8)(val & 0xf); + gpu->page_base_y = (u8)((val >> 4) & 1); + gpu->semi_transparency = (u8)((val >> 5) & 3); + + /* Thought i would try ternary but I am not sure if this actually works + gpu->texture_depth = (val >> 7 & 3) ? 0 ? TD_T4BIT ? 1 ? TD_T8BIT ? 2 ? TD_T15BIT : 0 : 0 : 0 : 0 : 0 : 0;*/ + + switch ((val >> 7) & 3) + { + case 0: gpu->texture_depth = TD_T4BIT; break; + case 1: gpu->texture_depth = TD_T8BIT; break; + case 2: gpu->texture_depth = TD_T15BIT; break; + default: fprintf(stderr, "Unhandled texture depth %d\n", (val >> 7) & 3); exit(1); + } + +} diff --git a/src/gpu.h b/src/gpu.h @@ -1,5 +1,36 @@ #pragma once +#include "types.h" + +typedef enum _TEXTURE_DEPTH { + TD_T4BIT, + TD_T8BIT, + TD_T15BIT, +} TEXTURE_DEPTH; + +typedef enum _FIELD { + F_TOP, + F_BOTTOM, +} FIELD; + +typedef enum _DMA_DIRECTION { + DMA_DIR_OFF, + DMA_DIR_FIFO, + DMA_DIR_CPUTOGP0, + DMA_DIR_VRAMTOCPU +} DMA_DIRECTION; + +typedef enum _VMODE { + VMODE_NTSC, + VMODE_PAL, +} VMODE; + +typedef enum _DISPLAY_DEPTH { + DISP_DEPTH_D15BITS, + DISP_DEPTH_D24BITS, +} DISPLAY_DEPTH; + +/* line 1045 in no$psx docs */ typedef struct _GPU { u8 page_base_x; u8 page_base_y; @@ -14,20 +45,18 @@ typedef struct _GPU { u8 hres; u8 vres; VMODE vmode; - DISPLAY_DEPTH diplay_depth; + DISPLAY_DEPTH display_depth; u8 interlaced; u8 display_disabled; u8 interrupt; DMA_DIRECTION dma_direction; -} GPU; -typdef enum _TEXTURE_DEPTH { - TD_T4BIT, - TD_T8BIT, - TD_T15BIT, -} TEXTURE_DEPTH; + u8 rectangle_texture_x_flip; + u8 rectangle_texture_y_flip; +} GPU; -typedef enum _FIELD { - F_TOP, - F_BOTTOM, -} FIELD; +u8 HOR_RES_from_fields(u8, u8); +u32 HOR_RES_into_status(u8); +void GPU_gp0(GPU*, u32); +void GPU_gp0_draw_mode(GPU*, u32); +GPU* GPU_new(void); diff --git a/src/interconnect.c b/src/interconnect.c @@ -58,10 +58,10 @@ INTER_load16(Interconnect* inter, u32 addr) { u32 offset; u32 abs_addr; - u32 contains; + u32 contains; offset = 0; - contains = 0; + contains = 0; abs_addr = mask_region(addr); if (addr % 2 != 0) @@ -73,12 +73,12 @@ INTER_load16(Interconnect* inter, u32 addr) /* Assert abs_address Mappings */ contains = UTIL_contains(SPU_START, SPU_SIZE, abs_addr, &offset); if (contains) - { + { #ifndef DEBUG - fprintf(stderr, "Unhandled read from SPU register: %08X\n", offset); + fprintf(stderr, "Unhandled read from SPU register: %08X\n", offset); #endif - return 0; - } + return 0; + } contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); if (contains) @@ -96,15 +96,15 @@ INTER_load16(Interconnect* inter, u32 addr) PANIC("Unhandled Load16 At Address %08X\n", abs_addr); } -u32 + u32 INTER_load32(Interconnect* inter, u32 addr) { u32 offset; u32 abs_addr; - u32 contains; + u32 contains; offset = 0; - contains = 0; + contains = 0; abs_addr = mask_region(addr); if (addr % 4 != 0) @@ -143,7 +143,7 @@ INTER_load32(Interconnect* inter, u32 addr) contains = UTIL_contains(DMA_START, DMA_SIZE, abs_addr, &offset); if (contains) { - return INTER_dma_reg(inter, offset); + return INTER_dma_reg(inter, offset); } contains = UTIL_contains(GPU_START, GPU_SIZE, abs_addr, &offset); @@ -153,17 +153,17 @@ INTER_load32(Interconnect* inter, u32 addr) printf("GPU read %08X\n", abs_addr); #endif - switch(offset) - { - case 4: return 0x1c000000; - default: return 0; - } + switch(offset) + { + case 4: return 0x1c000000; + default: return 0; + } } PANIC("Unhandled Load32 At Address %08X\n", addr); } -void + void INTER_store8(Interconnect* inter, u32 addr, u8 val) { u32 offset; @@ -193,7 +193,7 @@ INTER_store8(Interconnect* inter, u32 addr, u8 val) PANIC("Unhandled store8 into abs_address: %08X\n", abs_addr); } -void + void INTER_store16(Interconnect* inter, u32 addr, u16 val) { u32 offset; @@ -231,7 +231,7 @@ INTER_store16(Interconnect* inter, u32 addr, u16 val) contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); if (contains) { - RAM_store16(inter->ram, offset, val); + RAM_store16(inter->ram, offset, val); return; } @@ -239,7 +239,7 @@ INTER_store16(Interconnect* inter, u32 addr, u16 val) if (contains) { #ifndef DEBUG - printf("IRQ control write %08X at address %08X\n", val, offset); + printf("IRQ control write %08X at address %08X\n", val, offset); #endif return; } @@ -247,22 +247,22 @@ 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; - u32 contains; + u32 contains; u32 abs_addr; - offset = 0; - contains = 0; + offset = 0; + contains = 0; abs_addr = mask_region(addr); if (addr % 4 != 0) { #ifndef DEBUG fprintf(stderr, "Unaligned_store32_address: %08X", addr); #endif - } + } contains = UTIL_contains(RAM_START, RAM_SIZE, abs_addr, &offset); if (contains) @@ -351,90 +351,90 @@ INTER_store32(Interconnect* inter, u32 addr, u32 val) PANIC("Unhandled store32 into abs_address: %08X\n", addr); } -u32 + u32 INTER_dma_reg(Interconnect* inter, u32 offset) { u32 major, minor, val; - Channel* channel; + Channel* channel; major = (offset & 0x70) >> 4; minor = offset & 0xf; switch (major) { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: - //if ((Port)major < 0) { - // fprintf(stderr, "WHATTTTTTTTT"); - // exit(1); - //} - - channel = &inter->dma->channels[(Port)major]; - switch (minor) { - case 0: val = CHANNEL_base(channel); break; - case 4: val = CHANNEL_block_control(channel); break; - case 8: val = CHANNEL_control(channel); break; - default: fprintf(stderr, "Unhandled DMA read at %08X\n", offset); exit(EXIT_FAILURE); - } - break; - case 7: - switch (minor) { - case 0: val = DMA_control(inter->dma); break; - case 4: val = DMA_interrupt(inter->dma); break; + case 0: case 1: case 2: case 3: case 4: case 5: case 6: + //if ((Port)major < 0) { + // fprintf(stderr, "WHATTTTTTTTT"); + // exit(1); + //} + + channel = &inter->dma->channels[(Port)major]; + switch (minor) { + case 0: val = CHANNEL_base(channel); break; + case 4: val = CHANNEL_block_control(channel); break; + case 8: val = CHANNEL_control(channel); break; + default: fprintf(stderr, "Unhandled DMA read at %08X\n", offset); exit(EXIT_FAILURE); + } + break; + case 7: + switch (minor) { + case 0: val = DMA_control(inter->dma); break; + case 4: val = DMA_interrupt(inter->dma); break; + default: fprintf(stderr, "unhandled DMA access %08X\n", offset); exit(EXIT_FAILURE); + } + break; default: fprintf(stderr, "unhandled DMA access %08X\n", offset); exit(EXIT_FAILURE); - } - break; - default: fprintf(stderr, "unhandled DMA access %08X\n", offset); exit(EXIT_FAILURE); } return val; } -void + void INTER_set_dma_reg(Interconnect* inter, u32 offset, u32 val) { u32 major, minor; - Channel* channel; - Port port, active_port; + Channel* channel; + Port port, active_port; major = (offset & 0x70) >> 4; minor = offset & 0xf; active_port = PORT_INVALID; switch (major) { - case 0: case 1: case 2: case 3: case 4: case 5: case 6: - - port = (Port)major; - channel = &inter->dma->channels[port]; - - switch (minor) { - case 0: CHANNEL_set_base(channel, val); break; - case 4: CHANNEL_set_block_control(channel, val); break; - case 8: CHANNEL_set_control(channel, val); break; - default: fprintf(stderr, "Unhandled DMA write at %08X\n", offset); exit(EXIT_FAILURE); - } - if (CHANNEL_active(channel)) { - active_port = port; - } else { - active_port = PORT_INVALID; - } - break; - case 7: - switch (minor) { - case 0: DMA_set_control(inter->dma, val); break; - case 4: DMA_set_interrupt(inter->dma, val); break; - default: active_port = PORT_INVALID; break;// fprintf(stderr, "unhandled DMA write %08X\n", offset); exit(EXIT_FAILURE); - } - break; - default: fprintf(stderr, "unhandled DMA write %08X\n", offset); exit(EXIT_FAILURE); + case 0: case 1: case 2: case 3: case 4: case 5: case 6: + + port = (Port)major; + channel = &inter->dma->channels[port]; + + switch (minor) { + case 0: CHANNEL_set_base(channel, val); break; + case 4: CHANNEL_set_block_control(channel, val); break; + case 8: CHANNEL_set_control(channel, val); break; + default: fprintf(stderr, "Unhandled DMA write at %08X\n", offset); exit(EXIT_FAILURE); + } + if (CHANNEL_active(channel)) { + active_port = port; + } else { + active_port = PORT_INVALID; + } + break; + case 7: + switch (minor) { + case 0: DMA_set_control(inter->dma, val); break; + case 4: DMA_set_interrupt(inter->dma, val); break; + default: active_port = PORT_INVALID; break;// fprintf(stderr, "unhandled DMA write %08X\n", offset); exit(EXIT_FAILURE); + } + break; + default: fprintf(stderr, "unhandled DMA write %08X\n", offset); exit(EXIT_FAILURE); } - if (active_port != PORT_INVALID) - INTER_do_dma(inter, (Port)active_port); + if (active_port != PORT_INVALID) + INTER_do_dma(inter, (Port)active_port); } -void + void INTER_do_dma(Interconnect* inter, Port port) { Channel* ch; if (port == PORT_INVALID) { - printf("%d\n", port); + printf("%d\n", port); fprintf(stderr, "Invalid port doing dma\n"); exit(EXIT_FAILURE); } @@ -442,8 +442,8 @@ INTER_do_dma(Interconnect* inter, Port port) ch = &inter->dma->channels[(Port)port]; switch (ch->sync) { - case SYNC_LINKED_LIST: INTER_do_dma_linked_list(inter, port); break; - default: INTER_do_dma_block(inter, port); break; + case SYNC_LINKED_LIST: INTER_do_dma_linked_list(inter, port); break; + default: INTER_do_dma_block(inter, port); break; } } @@ -452,69 +452,69 @@ INTER_do_dma_block(Interconnect* inter, Port port) { Channel *ch; u32 addr; - u32 increment; - u32 src_word; - u32 remsz; + u32 increment; + u32 src_word; + u32 remsz; ch = &inter->dma->channels[port]; - remsz = 0; + remsz = 0; switch (ch->step) { - case STEP_INCREMENT: increment = 4; break; - case STEP_DECREMENT: increment = -4; break; - default: fprintf(stderr, "Unreachable!\n"); exit(EXIT_FAILURE); + case STEP_INCREMENT: increment = 4; break; + case STEP_DECREMENT: increment = -4; break; + default: fprintf(stderr, "Unreachable!\n"); exit(EXIT_FAILURE); } - addr = ch->base; + addr = ch->base; - // printf("%d\n", port); - // printf("%08X %08X %d\n", ch->block_size, ch->block_count, (Port)ch->step); + // printf("%d\n", port); + // printf("%08X %08X %d\n", ch->block_size, ch->block_count, (Port)ch->step); - if (!CHANNEL_transfer_size(ch, &remsz)) { - fprintf(stderr, "Couldn't figure out DMA block transfer size\n"); - exit(EXIT_FAILURE); - } + if (!CHANNEL_transfer_size(ch, &remsz)) { + fprintf(stderr, "Couldn't figure out DMA block transfer size\n"); + exit(EXIT_FAILURE); + } - while (remsz > 0) { - u32 cur_addr; - cur_addr = addr & 0x1ffffc; + while (remsz > 0) { + u32 cur_addr; + cur_addr = addr & 0x1ffffc; - switch (ch->direction) { - case DIR_FROM_RAM: - src_word = RAM_load32(inter->ram, cur_addr); - switch(port) { - case PORT_GPU: + switch (ch->direction) { + case DIR_FROM_RAM: + src_word = RAM_load32(inter->ram, cur_addr); + switch(port) { + case PORT_GPU: #ifndef DEBUG - printf("GPU data %08X\n", src_word); + printf("GPU data %08X\n", src_word); #endif - break; - default: - fprintf(stderr, "Unhandled DMA destination port: %d", (u8)port); - exit(EXIT_FAILURE); - } - break; - case DIR_TO_RAM: - switch(port) { - case PORT_OTC: - if (remsz == 1) { - src_word = 0xffffff; - } else { - src_word = (addr - 4) & 0x1fffff; - } - break; - default: - fprintf(stderr, "Unhandled DMA source port: %d", (u8)port); - exit(EXIT_FAILURE); - } - RAM_store32(inter->ram, cur_addr, src_word); - break; - default: break; - } - - addr += increment; - remsz--; - } - CHANNEL_done(ch); + break; + default: + fprintf(stderr, "Unhandled DMA destination port: %d", (u8)port); + exit(EXIT_FAILURE); + } + break; + case DIR_TO_RAM: + switch(port) { + case PORT_OTC: + if (remsz == 1) { + src_word = 0xffffff; + } else { + src_word = (addr - 4) & 0x1fffff; + } + break; + default: + fprintf(stderr, "Unhandled DMA source port: %d", (u8)port); + exit(EXIT_FAILURE); + } + RAM_store32(inter->ram, cur_addr, src_word); + break; + default: break; + } + + addr += increment; + remsz--; + } + CHANNEL_done(ch); } void @@ -524,36 +524,36 @@ INTER_do_dma_linked_list(Interconnect* inter, Port port) u32 addr, header, remsz, command; ch = &inter->dma->channels[port]; - addr = ch->base & 0x1ffffc; + addr = ch->base & 0x1ffffc; - if (ch->direction == DIR_TO_RAM) { - fprintf(stderr, "Invalid DMA direction for linked list mode\n"); - exit(EXIT_FAILURE); - } + if (ch->direction == DIR_TO_RAM) { + fprintf(stderr, "Invalid DMA direction for linked list mode\n"); + exit(EXIT_FAILURE); + } - if (port != PORT_GPU) { - fprintf(stderr, "Attempted linked list DMA on port %d\n", (u8)port); - exit(EXIT_FAILURE); - } + if (port != PORT_GPU) { + fprintf(stderr, "Attempted linked list DMA on port %d\n", (u8)port); + exit(EXIT_FAILURE); + } - while (1) { - header = RAM_load32(inter->ram, addr); - remsz = header >> 24; + while (1) { + header = RAM_load32(inter->ram, addr); + remsz = header >> 24; - while (remsz > 0) { - addr = (addr + 4) & 0x1ffffc; - command = RAM_load32(inter->ram, addr); + while (remsz > 0) { + addr = (addr + 4) & 0x1ffffc; + command = RAM_load32(inter->ram, addr); #ifndef DEBUG - printf("GPU command %08X\n", command); + printf("GPU command %08X\n", command); #endif - remsz--; - } + remsz--; + } - if ((header & 0x800000) != 0) - break; + if ((header & 0x800000) != 0) + break; - addr = header & 0x1ffffc; + addr = header & 0x1ffffc; - } - CHANNEL_done(ch); + } + CHANNEL_done(ch); } diff --git a/src/main.c b/src/main.c @@ -8,11 +8,13 @@ #include "bios.h" #include "mem.h" #include "defs.h" +#include "gpu.h" int main(int argc, char **argv) { CPU* cpu; + GPU* gpu; Interconnect* inter; inter = new_interconnect(); diff --git a/test.cc b/test.cc @@ -37,6 +37,12 @@ int main() { + /* Thought i would try ternary but I am not sure if this actually works */ + int val = 800; + int test = (val >> 7 & 3) ? 0 ? 100 ? 1 ? 200 ? 2 ? 300 : 0 : 0 : 0 : 0 : 0 : 0; + + printf("\n%d\n", test); + FOO::fyk a; FOO::ho x = FOO::ONE;