diff --git a/frontend/main.c b/frontend/main.c index d546d7b..4298267 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -18,7 +18,7 @@ int main(int argc, const char* argv[]) { psxe_screen_set_scale(screen, 2); psxe_screen_reload(screen); - psx_gpu_set_dmode_event_callback(gpu, psxe_gpu_dmode_event_cb); + psx_gpu_set_event_callback(gpu, GPU_EVENT_DMODE, psxe_gpu_dmode_event_cb); psx_gpu_set_udata(gpu, 0, screen); if (argv[1]) { @@ -31,6 +31,18 @@ int main(int argc, const char* argv[]) { psxe_screen_update(screen); } + psx_cpu_t* cpu = psx_get_cpu(psx); + + log_fatal("r0=%08x at=%08x v0=%08x v1=%08x", cpu->r[0] , cpu->r[1] , cpu->r[2] , cpu->r[3] ); + log_fatal("a0=%08x a1=%08x a2=%08x a3=%08x", cpu->r[4] , cpu->r[5] , cpu->r[6] , cpu->r[7] ); + log_fatal("t0=%08x t1=%08x t2=%08x t3=%08x", cpu->r[8] , cpu->r[9] , cpu->r[10], cpu->r[11]); + log_fatal("t4=%08x t5=%08x t6=%08x t7=%08x", cpu->r[12], cpu->r[13], cpu->r[14], cpu->r[15]); + log_fatal("s0=%08x s1=%08x s2=%08x s3=%08x", cpu->r[16], cpu->r[17], cpu->r[18], cpu->r[19]); + log_fatal("s4=%08x s5=%08x s6=%08x s7=%08x", cpu->r[20], cpu->r[21], cpu->r[22], cpu->r[23]); + log_fatal("t8=%08x t9=%08x k0=%08x k1=%08x", cpu->r[24], cpu->r[25], cpu->r[26], cpu->r[27]); + log_fatal("gp=%08x sp=%08x fp=%08x ra=%08x", cpu->r[28], cpu->r[29], cpu->r[30], cpu->r[31]); + log_fatal("pc=%08x hi=%08x lo=%08x", cpu->pc, cpu->hi, cpu->lo); + psx_destroy(psx); psxe_screen_destroy(screen); diff --git a/frontend/screen.c b/frontend/screen.c index c58c0ad..95b9a46 100644 --- a/frontend/screen.c +++ b/frontend/screen.c @@ -7,13 +7,19 @@ psxe_screen_t* psxe_screen_create() { void psxe_screen_init(psxe_screen_t* screen, psx_gpu_t* gpu) { memset(screen, 0, sizeof(psxe_screen_t)); +#ifdef PSXE_SCREEN_DEBUG + screen->width = PSX_GPU_FB_WIDTH; + screen->height = PSX_GPU_FB_HEIGHT; +#else screen->width = 320; screen->height = 240; +#endif screen->scale = 1; screen->format = SDL_PIXELFORMAT_BGR555; screen->mode = 60; - screen->buf = (uint32_t*)gpu->vram; + screen->buf = gpu->vram; screen->open = 1; + screen->gpu = gpu; SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); } @@ -52,7 +58,9 @@ int psxe_screen_is_open(psxe_screen_t* screen) { } void psxe_screen_update(psxe_screen_t* screen) { - SDL_UpdateTexture(screen->texture, NULL, screen->buf, PSX_GPU_FB_WIDTH * sizeof(uint16_t)); + uint32_t disp_offset = screen->gpu->disp_x + (screen->gpu->disp_y * 1024); + + SDL_UpdateTexture(screen->texture, NULL, screen->buf + disp_offset, PSX_GPU_FB_WIDTH * sizeof(uint16_t)); SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL); SDL_RenderPresent(screen->renderer); @@ -84,12 +92,18 @@ void psxe_screen_destroy(psxe_screen_t* screen) { void psxe_gpu_dmode_event_cb(psx_gpu_t* gpu) { psxe_screen_t* screen = gpu->udata[0]; +#ifdef PSXE_SCREEN_DEBUG + screen->width = PSX_GPU_FB_WIDTH; // dmode_hres_table[gpu->display_mode & 0x3]; + screen->height = PSX_GPU_FB_HEIGHT; // (gpu->display_mode & 0x4) ? 480 : 240; +#else static int dmode_hres_table[] = { 256, 320, 512, 640 }; screen->width = dmode_hres_table[gpu->display_mode & 0x3]; screen->height = (gpu->display_mode & 0x4) ? 480 : 240; +#endif + screen->format = gpu->display_mode & 0x10 ? SDL_PIXELFORMAT_BGR888 : SDL_PIXELFORMAT_BGR555; screen->mode = gpu->display_mode & 0x8 ? 60 : 50; diff --git a/frontend/screen.h b/frontend/screen.h index c2add63..4f7c017 100644 --- a/frontend/screen.h +++ b/frontend/screen.h @@ -12,12 +12,14 @@ typedef struct { SDL_Renderer* renderer; SDL_Texture* texture; + psx_gpu_t* gpu; + unsigned int width, height, scale; unsigned int format; unsigned int mode; int open; - uint32_t* buf; + uint16_t* buf; } psxe_screen_t; psxe_screen_t* psxe_screen_create(); diff --git a/psx/cpu.c b/psx/cpu.c index d88f6f1..fec5146 100644 --- a/psx/cpu.c +++ b/psx/cpu.c @@ -288,6 +288,7 @@ void psx_cpu_load_state(psx_cpu_t* cpu, FILE* file) { void psx_cpu_cycle(psx_cpu_t* cpu) { if ((cpu->pc & 0x3fffffff) == 0x000000a4) if (cpu->a_function_hook) cpu->a_function_hook(cpu); + if ((cpu->pc & 0x3fffffff) == 0x000000b4) if (cpu->a_function_hook) cpu->b_function_hook(cpu); @@ -300,6 +301,11 @@ void psx_cpu_cycle(psx_cpu_t* cpu) { g_psx_cpu_primary_table[OP](cpu); + // Interrupts not yet working + // if ((cpu->cop0_sr & SR_IEC) && (cpu->cop0_cause & cpu->cop0_sr & SR_IM)) { + // psx_cpu_exception(cpu, CAUSE_INT); + // } + cpu->r[0] = 0; } @@ -325,9 +331,12 @@ void psx_cpu_exception(psx_cpu_t* cpu, uint32_t cause) { cpu->pc = (cpu->cop0_sr & SR_BEV) ? 0xbfc00180 : 0x80000080; // Simulate pipeline flush - cpu->buf[0] = psx_bus_read32(cpu->bus, cpu->pc); + psx_cpu_fetch(cpu); +} - cpu->pc += 4; +void psx_cpu_irq(psx_cpu_t* cpu, uint32_t irq) { + // Set interrupt pending field + cpu->cop0_cause |= irq << 10; } void psx_cpu_i_invalid(psx_cpu_t* cpu) { diff --git a/psx/cpu.h b/psx/cpu.h index 1f0d2ed..06e59a3 100644 --- a/psx/cpu.h +++ b/psx/cpu.h @@ -166,6 +166,7 @@ void psx_cpu_init(psx_cpu_t*, psx_bus_t*); void psx_cpu_destroy(psx_cpu_t*); void psx_cpu_cycle(psx_cpu_t*); void psx_cpu_exception(psx_cpu_t*, uint32_t); +void psx_cpu_irq(psx_cpu_t*, uint32_t); void psx_cpu_load_state(psx_cpu_t*, FILE*); void psx_cpu_save_state(psx_cpu_t*, FILE*); void psx_cpu_fetch(psx_cpu_t*); diff --git a/psx/dev/gpu.c b/psx/dev/gpu.c index bdea9ab..03fb72e 100644 --- a/psx/dev/gpu.c +++ b/psx/dev/gpu.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "gpu.h" #include "../log.h" @@ -15,7 +16,7 @@ psx_gpu_t* psx_gpu_create() { return (psx_gpu_t*)malloc(sizeof(psx_gpu_t)); } -void psx_gpu_init(psx_gpu_t* gpu) { +void psx_gpu_init(psx_gpu_t* gpu, psx_ic_t* ic) { memset(gpu, 0, sizeof(psx_gpu_t)); gpu->io_base = PSX_GPU_BEGIN; @@ -23,12 +24,14 @@ void psx_gpu_init(psx_gpu_t* gpu) { gpu->vram = (uint16_t*)malloc(PSX_GPU_VRAM_SIZE); gpu->state = GPU_STATE_RECV_CMD; + + gpu->ic = ic; } uint32_t psx_gpu_read32(psx_gpu_t* gpu, uint32_t offset) { switch (offset) { - case 0x00: return 0x00000000; // GPUREAD - case 0x04: return 0x1c000000; // GPUSTAT + case 0x00: return gpu->gpuread; // GPUREAD + case 0x04: return gpu->gpustat; // GPUSTAT } log_warn("Unhandled 32-bit GPU read at offset %08x", offset); @@ -58,7 +61,100 @@ uint8_t psx_gpu_read8(psx_gpu_t* gpu, uint32_t offset) { return 0x0; } +int min(int x0, int x1) { + return (x0 < x1) ? x0 : x1; +} + +int max(int x0, int x1) { + return (x0 > x1) ? x0 : x1; +} + +#define EDGE(a, b, c) ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) + void gpu_render_flat_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, uint32_t color) { + vertex_t a, b, c; + + a = v0; + + /* Ensure the winding order is correct */ + if (EDGE(v0, v1, v2) < 0) { + b = v2; + c = v1; + } else { + b = v1; + c = v2; + } + + a.x += gpu->off_x; + a.y += gpu->off_y; + b.x += gpu->off_x; + b.y += gpu->off_y; + c.x += gpu->off_x; + c.y += gpu->off_y; + + int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1); + int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1); + int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2); + int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2); + + for (int y = ymin; y < ymax; y++) { + for (int x = xmin; x < xmax; x++) { + int z0 = ((b.x - a.x) * (y - a.y)) - ((b.y - a.y) * (x - a.x)); + int z1 = ((c.x - b.x) * (y - b.y)) - ((c.y - b.y) * (x - b.x)); + int z2 = ((a.x - c.x) * (y - c.y)) - ((a.y - c.y) * (x - c.x)); + + if ((z0 >= 0) && (z1 >= 0) && (z2 >= 0)) { + gpu->vram[x + (y * 1024)] = gpu_to_bgr555(color); + } + } + } +} + +void gpu_render_shaded_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2) { + vertex_t a, b, c; + + a = v0; + + /* Ensure the winding order is correct */ + if (EDGE(v0, v1, v2) < 0) { + b = v2; + c = v1; + } else { + b = v1; + c = v2; + } + + a.x += gpu->off_x; + a.y += gpu->off_y; + b.x += gpu->off_x; + b.y += gpu->off_y; + c.x += gpu->off_x; + c.y += gpu->off_y; + + int xmin = max(min(min(a.x, b.x), c.x), gpu->draw_x1); + int ymin = max(min(min(a.y, b.y), c.y), gpu->draw_y1); + int xmax = min(max(max(a.x, b.x), c.x), gpu->draw_x2); + int ymax = min(max(max(a.y, b.y), c.y), gpu->draw_y2); + + int area = EDGE(a, b, c); + + for (int y = ymin; y < ymax; y++) { + for (int x = xmin; x < xmax; x++) { + int z0 = ((b.x - a.x) * (y - a.y)) - ((b.y - a.y) * (x - a.x)); + int z1 = ((c.x - b.x) * (y - b.y)) - ((c.y - b.y) * (x - b.x)); + int z2 = ((a.x - c.x) * (y - c.y)) - ((a.y - c.y) * (x - c.x)); + + if ((z0 >= 0) && (z1 >= 0) && (z2 >= 0)) { + uint32_t cr = (z0 * ((a.c >> 0) & 0xff) + z1 * ((b.c >> 0) & 0xff) + z2 * ((c.c >> 0) & 0xff)) / area; + uint32_t cg = (z0 * ((a.c >> 8) & 0xff) + z1 * ((b.c >> 8) & 0xff) + z2 * ((c.c >> 8) & 0xff)) / area; + uint32_t cb = (z0 * ((a.c >> 16) & 0xff) + z1 * ((b.c >> 16) & 0xff) + z2 * ((c.c >> 16) & 0xff)) / area; + + uint32_t color = (cb << 16) | (cg << 8) | cr; + + gpu->vram[x + (y * 1024)] = gpu_to_bgr555(color); + } + } + } } void gpu_cmd_a0(psx_gpu_t* gpu) { @@ -132,9 +228,9 @@ void gpu_cmd_02(psx_gpu_t* gpu) { gpu->color ); - for (int y = gpu->ypos; y < gpu->ysiz; y++) { - for (int x = gpu->xpos; x < gpu->xsiz; x++) { - ((uint16_t*)gpu->vram)[x + (y * 512)] = 0x0000; + for (int y = 0; y < gpu->ysiz; y++) { + for (int x = 0; x < gpu->xsiz; x++) { + gpu->vram[(x + gpu->xpos) + ((y + gpu->ypos) * 1024)] = gpu_to_bgr555(gpu->color); } } @@ -144,10 +240,141 @@ void gpu_cmd_02(psx_gpu_t* gpu) { } } +// Monochrome Opaque Quadrilateral +void gpu_cmd_28(psx_gpu_t* gpu) { + switch (gpu->state) { + case GPU_STATE_RECV_CMD: { + gpu->state = GPU_STATE_RECV_ARGS; + gpu->cmd_args_remaining = 4; + } break; + + case GPU_STATE_RECV_ARGS: { + if (!gpu->cmd_args_remaining) { + gpu->state = GPU_STATE_RECV_DATA; + + gpu->v0.x = gpu->buf[1] & 0xffff; + gpu->v0.y = gpu->buf[1] >> 16; + gpu->v1.x = gpu->buf[2] & 0xffff; + gpu->v1.y = gpu->buf[2] >> 16; + gpu->v2.x = gpu->buf[3] & 0xffff; + gpu->v2.y = gpu->buf[3] >> 16; + gpu->v3.x = gpu->buf[4] & 0xffff; + gpu->v3.y = gpu->buf[4] >> 16; + gpu->color = gpu->buf[0] & 0xffffff; + + gpu_render_flat_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, gpu->color); + gpu_render_flat_triangle(gpu, gpu->v1, gpu->v2, gpu->v3, gpu->color); + + gpu->state = GPU_STATE_RECV_CMD; + } + } break; + } +} + +// Monochrome Opaque Quadrilateral +void gpu_cmd_30(psx_gpu_t* gpu) { + switch (gpu->state) { + case GPU_STATE_RECV_CMD: { + gpu->state = GPU_STATE_RECV_ARGS; + gpu->cmd_args_remaining = 5; + } break; + + case GPU_STATE_RECV_ARGS: { + if (!gpu->cmd_args_remaining) { + gpu->state = GPU_STATE_RECV_DATA; + + gpu->v0.c = gpu->buf[0] & 0xffffff; + gpu->v0.x = gpu->buf[1] & 0xffff; + gpu->v0.y = gpu->buf[1] >> 16; + gpu->v1.c = gpu->buf[2] & 0xffffff; + gpu->v1.x = gpu->buf[3] & 0xffff; + gpu->v1.y = gpu->buf[3] >> 16; + gpu->v2.c = gpu->buf[4] & 0xffffff; + gpu->v2.x = gpu->buf[5] & 0xffff; + gpu->v2.y = gpu->buf[5] >> 16; + + gpu_render_flat_triangle(gpu, gpu->v0, gpu->v1, gpu->v2, gpu->color); + + gpu->state = GPU_STATE_RECV_CMD; + } + } break; + } +} + +// Monochrome Opaque Quadrilateral +void gpu_cmd_38(psx_gpu_t* gpu) { + switch (gpu->state) { + case GPU_STATE_RECV_CMD: { + gpu->state = GPU_STATE_RECV_ARGS; + gpu->cmd_args_remaining = 7; + } break; + + case GPU_STATE_RECV_ARGS: { + if (!gpu->cmd_args_remaining) { + gpu->state = GPU_STATE_RECV_DATA; + + gpu->v0.c = gpu->buf[0] & 0xffffff; + gpu->v0.x = gpu->buf[1] & 0xffff; + gpu->v0.y = gpu->buf[1] >> 16; + gpu->v1.c = gpu->buf[2] & 0xffffff; + gpu->v1.x = gpu->buf[3] & 0xffff; + gpu->v1.y = gpu->buf[3] >> 16; + gpu->v2.c = gpu->buf[4] & 0xffffff; + gpu->v2.x = gpu->buf[5] & 0xffff; + gpu->v2.y = gpu->buf[5] >> 16; + gpu->v3.c = gpu->buf[6] & 0xffffff; + gpu->v3.x = gpu->buf[7] & 0xffff; + gpu->v3.y = gpu->buf[7] >> 16; + + log_fatal("v0=(%u, %u, %06x), v1=(%u, %u, %06x), v2=(%u, %u, %06x), v3=(%u, %u, %06x)", + gpu->v0.x, gpu->v0.y, gpu->v0.c, + gpu->v1.x, gpu->v1.y, gpu->v1.c, + gpu->v2.x, gpu->v2.y, gpu->v2.c, + gpu->v3.x, gpu->v3.y, gpu->v3.c + ); + + gpu_render_shaded_triangle(gpu, gpu->v1, gpu->v0, gpu->v2); + gpu_render_shaded_triangle(gpu, gpu->v3, gpu->v2, gpu->v1); + + gpu->state = GPU_STATE_RECV_CMD; + } + } break; + } +} + void psx_gpu_update_cmd(psx_gpu_t* gpu) { switch (gpu->buf[0] >> 24) { + case 0x00: /* nop */ break; case 0x02: gpu_cmd_02(gpu); break; + case 0x28: gpu_cmd_28(gpu); break; + case 0x30: gpu_cmd_30(gpu); break; + case 0x38: gpu_cmd_38(gpu); break; case 0xa0: gpu_cmd_a0(gpu); break; + case 0xe1: { + gpu->gpustat = (gpu->buf[0] & 0x7ff) | 0x1c000000; + } break; + case 0xe2: { + gpu->texw_mx = (gpu->buf[0] >> 0 ) & 0x1f; + gpu->texw_my = (gpu->buf[0] >> 5 ) & 0x1f; + gpu->texw_ox = (gpu->buf[0] >> 10) & 0x1f; + gpu->texw_oy = (gpu->buf[0] >> 15) & 0x1f; + } break; + case 0xe3: { + gpu->draw_x1 = (gpu->buf[0] >> 0 ) & 0x3ff; + gpu->draw_y1 = (gpu->buf[0] >> 10) & 0x1ff; + } break; + case 0xe4: { + gpu->draw_x2 = (gpu->buf[0] >> 0 ) & 0x3ff; + gpu->draw_y2 = (gpu->buf[0] >> 10) & 0x1ff; + } break; + case 0xe5: { + gpu->off_x = (gpu->buf[0] >> 0 ) & 0x7ff; + gpu->off_y = (gpu->buf[0] >> 11) & 0x7ff; + } break; + case 0xe6: { + /* To-do: Implement mask bit thing */ + } break; + default: log_fatal("Unhandled GP0(%02Xh)", gpu->buf[0] >> 24); break; } } @@ -188,9 +415,27 @@ void psx_gpu_write32(psx_gpu_t* gpu, uint32_t offset, uint32_t value) { case 0x08: gpu->display_mode = value & 0xffffff; - if (gpu->dmode_event_cb) - gpu->dmode_event_cb(gpu); + if (gpu->event_cb_table[GPU_EVENT_DMODE]) + gpu->event_cb_table[GPU_EVENT_DMODE](gpu); break; + + case 0x10: + switch (value & 7) { + case 2: + gpu->gpuread = ((gpu->texw_oy / 8) << 15) | ((gpu->texw_ox / 8) << 10) | ((gpu->texw_my / 8) << 5) | (gpu->texw_mx / 8); + break; + case 3: + gpu->gpuread = (gpu->draw_y1 << 10) | gpu->draw_x1; + break; + case 4: + gpu->gpuread = (gpu->draw_y2 << 10) | gpu->draw_x2; + break; + case 5: // Drawing Offset + gpu->gpuread = (gpu->off_y << 10) | gpu->off_x; + break; + default: + break; + } } log_error("GP1(%02Xh) args=%06x", value >> 24, value & 0xffffff); @@ -210,14 +455,18 @@ void psx_gpu_write8(psx_gpu_t* gpu, uint32_t offset, uint8_t value) { log_warn("Unhandled 8-bit GPU write at offset %08x (%02x)", offset, value); } -void psx_gpu_set_dmode_event_callback(psx_gpu_t* gpu, psx_gpu_event_callback_t cb) { - gpu->dmode_event_cb = cb; +void psx_gpu_set_event_callback(psx_gpu_t* gpu, int event, psx_gpu_event_callback_t cb) { + gpu->event_cb_table[event] = cb; } void psx_gpu_set_udata(psx_gpu_t* gpu, int index, void* udata) { gpu->udata[index] = udata; } +void psx_gpu_update(psx_gpu_t* gpu) { + // Do nothing for now +} + void psx_gpu_destroy(psx_gpu_t* gpu) { free(gpu->vram); free(gpu); diff --git a/psx/dev/gpu.h b/psx/dev/gpu.h index 5d8f491..5cad1e8 100644 --- a/psx/dev/gpu.h +++ b/psx/dev/gpu.h @@ -5,6 +5,8 @@ #include #include +#include "ic.h" + #define PSX_GPU_BEGIN 0x1f801810 #define PSX_GPU_SIZE 0x8 #define PSX_GPU_END 0x1f801814 @@ -14,6 +16,11 @@ #define PSX_GPU_VRAM_SIZE (0x100000) +enum { + GPU_EVENT_DMODE, + GPU_EVENT_VBLANK +}; + enum { GPU_STATE_RECV_CMD, GPU_STATE_RECV_ARGS, @@ -27,6 +34,11 @@ typedef struct psx_gpu_t psx_gpu_t; typedef void (*psx_gpu_cmd_t)(psx_gpu_t*); typedef void (*psx_gpu_event_callback_t)(psx_gpu_t*); +typedef struct { + int32_t x, y; + uint32_t c, t; +} vertex_t; + struct psx_gpu_t { uint32_t io_base, io_size; @@ -47,6 +59,7 @@ struct psx_gpu_t { uint32_t xsiz, ysiz; uint32_t addr; uint32_t xcnt, ycnt; + vertex_t v0, v1, v2, v3; // GPU state uint32_t state; @@ -66,18 +79,21 @@ struct psx_gpu_t { uint32_t texw_mx, texw_my; uint32_t texw_ox, texw_oy; + // CLUT offset uint32_t clut_x, clut_y; - psx_gpu_event_callback_t dmode_event_cb; + // Display area + uint32_t disp_x, disp_y; + + uint32_t cycles; + + psx_ic_t* ic; + + psx_gpu_event_callback_t event_cb_table[8]; }; -typedef struct { - int32_t x, y; - uint32_t c, t; -} vertex_t; - psx_gpu_t* psx_gpu_create(); -void psx_gpu_init(psx_gpu_t*); +void psx_gpu_init(psx_gpu_t*, psx_ic_t*); uint32_t psx_gpu_read32(psx_gpu_t*, uint32_t); uint16_t psx_gpu_read16(psx_gpu_t*, uint32_t); uint8_t psx_gpu_read8(psx_gpu_t*, uint32_t); @@ -86,6 +102,7 @@ void psx_gpu_write16(psx_gpu_t*, uint32_t, uint16_t); void psx_gpu_write8(psx_gpu_t*, uint32_t, uint8_t); void psx_gpu_destroy(psx_gpu_t*); void psx_gpu_set_udata(psx_gpu_t*, int, void*); -void psx_gpu_set_dmode_event_callback(psx_gpu_t*, psx_gpu_event_callback_t); +void psx_gpu_set_event_callback(psx_gpu_t*, int, psx_gpu_event_callback_t); +void psx_gpu_update(psx_gpu_t*); #endif \ No newline at end of file diff --git a/psx/dev/ic.c b/psx/dev/ic.c index fbc6489..151fbec 100644 --- a/psx/dev/ic.c +++ b/psx/dev/ic.c @@ -3,26 +3,29 @@ #include #include "ic.h" + #include "../log.h" psx_ic_t* psx_ic_create() { return (psx_ic_t*)malloc(sizeof(psx_ic_t)); } -void psx_ic_init(psx_ic_t* ic) { +void psx_ic_init(psx_ic_t* ic, psx_cpu_t* cpu) { memset(ic, 0, sizeof(psx_ic_t)); ic->io_base = PSX_IC_BEGIN; ic->io_size = PSX_IC_SIZE; - ic->i_stat = 0x00000000; - ic->i_mask = 0x00000000; + ic->stat = 0x00000000; + ic->mask = 0x00000000; + + ic->cpu = cpu; } uint32_t psx_ic_read32(psx_ic_t* ic, uint32_t offset) { switch (offset) { - case 0x00: return ic->i_stat; - case 0x04: return ic->i_mask; + case 0x00: return ic->stat; + case 0x04: return ic->mask; } log_warn("Unhandled 32-bit IC read at offset %08x", offset); @@ -32,8 +35,8 @@ uint32_t psx_ic_read32(psx_ic_t* ic, uint32_t offset) { uint16_t psx_ic_read16(psx_ic_t* ic, uint32_t offset) { switch (offset) { - case 0x00: return ic->i_stat; - case 0x04: return ic->i_mask; + case 0x00: return ic->stat; + case 0x04: return ic->mask; } log_warn("Unhandled 16-bit IC read at offset %08x", offset); @@ -49,8 +52,8 @@ uint8_t psx_ic_read8(psx_ic_t* ic, uint32_t offset) { void psx_ic_write32(psx_ic_t* ic, uint32_t offset, uint32_t value) { switch (offset) { - case 0x00: ic->i_stat = value; break; - case 0x04: ic->i_mask = value; break; + case 0x00: ic->stat = value; break; + case 0x04: ic->mask = value; break; default: { log_warn("Unhandled 32-bit IC write at offset %08x (%08x)", offset, value); @@ -60,8 +63,8 @@ void psx_ic_write32(psx_ic_t* ic, uint32_t offset, uint32_t value) { void psx_ic_write16(psx_ic_t* ic, uint32_t offset, uint16_t value) { switch (offset) { - case 0x00: ic->i_stat = value; break; - case 0x04: ic->i_mask = value; break; + case 0x00: ic->stat = value; break; + case 0x04: ic->mask = value; break; default: { log_warn("Unhandled 16-bit IC write at offset %08x (%08x)", offset, value); @@ -73,6 +76,15 @@ void psx_ic_write8(psx_ic_t* ic, uint32_t offset, uint8_t value) { log_warn("Unhandled 8-bit IC write at offset %08x (%02x)", offset, value); } +void psx_ic_irq(psx_ic_t* ic, int id) { + if (!(ic->mask & id)) + return; + + ic->stat = id; + + psx_cpu_irq(ic->cpu, true); +} + void psx_ic_destroy(psx_ic_t* ic) { free(ic); } \ No newline at end of file diff --git a/psx/dev/ic.h b/psx/dev/ic.h index c25af60..b000e69 100644 --- a/psx/dev/ic.h +++ b/psx/dev/ic.h @@ -3,10 +3,41 @@ #include +#include "../cpu.h" + #define PSX_IC_BEGIN 0x1f801070 #define PSX_IC_SIZE 0x8 #define PSX_IC_END 0x1F801077 +/* + 0 IRQ0 VBLANK (PAL=50Hz, NTSC=60Hz) + 1 IRQ1 GPU Can be requested via GP0(1Fh) command (rarely used) + 2 IRQ2 CDROM + 3 IRQ3 DMA + 4 IRQ4 TMR0 Timer 0 aka Root Counter 0 (Sysclk or Dotclk) + 5 IRQ5 TMR1 Timer 1 aka Root Counter 1 (Sysclk or H-blank) + 6 IRQ6 TMR2 Timer 2 aka Root Counter 2 (Sysclk or Sysclk/8) + 7 IRQ7 Controller and Memory Card - Byte Received Interrupt + 8 IRQ8 SIO + 9 IRQ9 SPU + 10 IRQ10 Controller - Lightpen Interrupt (reportedly also PIO...?) + 11-15 Not used (always zero) + 16-31 Garbage +*/ +enum { + IC_VBLANK = 0x001, + IC_GPU = 0x002, + IC_CDROM = 0x004, + IC_DM = 0x008, + IC_TMR0 = 0x010, + IC_TMR1 = 0x020, + IC_TMR2 = 0x040, + IC_CTRL = 0x080, + IC_SIO = 0x100, + IC_SPU = 0x200, + IC_LP_PIO = 0x400 +}; + /* 1F801070h 2 I_STAT - Interrupt status register 1F801074h 2 I_MASK - Interrupt mask register @@ -15,18 +46,21 @@ typedef struct { uint32_t io_base, io_size; - uint16_t i_stat; - uint16_t i_mask; + uint16_t stat; + uint16_t mask; + + psx_cpu_t* cpu; } psx_ic_t; psx_ic_t* psx_ic_create(); -void psx_ic_init(psx_ic_t*); +void psx_ic_init(psx_ic_t*, psx_cpu_t*); uint32_t psx_ic_read32(psx_ic_t*, uint32_t); uint16_t psx_ic_read16(psx_ic_t*, uint32_t); uint8_t psx_ic_read8(psx_ic_t*, uint32_t); void psx_ic_write32(psx_ic_t*, uint32_t, uint32_t); void psx_ic_write16(psx_ic_t*, uint32_t, uint16_t); void psx_ic_write8(psx_ic_t*, uint32_t, uint8_t); +void psx_ic_irq(psx_ic_t*, int); void psx_ic_destroy(psx_ic_t*); #endif \ No newline at end of file diff --git a/psx/psx.c b/psx/psx.c index 58a6e38..37d056f 100644 --- a/psx/psx.c +++ b/psx/psx.c @@ -26,6 +26,7 @@ void psx_load_exe(psx_t* psx, const char* path) { void psx_update(psx_t* psx) { psx_cpu_cycle(psx->cpu); + psx_gpu_update(psx->gpu); } void psx_run_frame(psx_t* psx) { @@ -35,7 +36,7 @@ void psx_run_frame(psx_t* psx) { unsigned int counter = (float)PSX_CPU_SPEED / framerate; while (counter--) { - psx_cpu_cycle(psx->cpu); + psx_update(psx); } } @@ -78,9 +79,9 @@ void psx_init(psx_t* psx, const char* bios_path) { psx_mc1_init(psx->mc1); psx_mc2_init(psx->mc2); psx_mc3_init(psx->mc3); - psx_ic_init(psx->ic); + psx_ic_init(psx->ic, psx->cpu); psx_scratchpad_init(psx->scratchpad); - psx_gpu_init(psx->gpu); + psx_gpu_init(psx->gpu, psx->ic); psx_spu_init(psx->spu); psx_cpu_init(psx->cpu, psx->bus);