From b043b943449c64f14c220d78fe731cfa47143031 Mon Sep 17 00:00:00 2001 From: allkern Date: Tue, 11 Jun 2024 16:05:22 -0300 Subject: [PATCH] Many fixes Fixed multiple GPU bugs: poly seam, wrong rect colors, transparent overlap Implemented Namco GunCon support Implemented support from 4MB/8MB RAM --- compat.txt | 1 + frontend/main.c | 4 ++ frontend/screen.c | 41 ++++++++++++++ psx/bus.c | 6 ++ psx/dev/cdrom.c | 32 +++++++---- psx/dev/gpu.c | 112 ++++++++++++++++++++++-------------- psx/dev/input.h | 2 +- psx/dev/pad.c | 2 +- psx/dev/pad.h | 2 +- psx/dev/ram.c | 21 ++++--- psx/dev/ram.h | 9 ++- psx/input/guncon.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ psx/input/guncon.h | 67 ++++++++++++++++++++++ psx/input/sda.c | 2 +- psx/psx.c | 2 +- 15 files changed, 371 insertions(+), 70 deletions(-) create mode 100644 psx/input/guncon.c create mode 100644 psx/input/guncon.h diff --git a/compat.txt b/compat.txt index b194c7e..d1d052d 100644 --- a/compat.txt +++ b/compat.txt @@ -39,6 +39,7 @@ Time Gal & Ninja Hayate (Japan) (En,Ja) (Disc 2) (Ninja Hayate) *9 Tokimeki Memorial 2 (Japan) *1 Tomb Raider (USA) *8 Tony Hawk's Pro Skater (USA) *10 +Vib-Ribbon (Japan) *8 WipeOut (USA) *7 Yu-Gi-Oh! Forbidden Memories (USA) *1 diff --git a/frontend/main.c b/frontend/main.c index d389e22..08ec693 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -1,5 +1,6 @@ #include "../psx/psx.h" #include "../psx/input/sda.h" +#include "../psx/input/guncon.h" #include "../psx/disc/cue.h" #include "screen.h" @@ -75,6 +76,9 @@ int main(int argc, const char* argv[]) { psx_input_t* input = psx_input_create(); psx_input_init(input); + // psxi_guncon_t* controller = psxi_guncon_create(); + // psxi_guncon_init(controller); + // psxi_guncon_init_input(controller, input); psxi_sda_t* controller = psxi_sda_create(); psxi_sda_init(controller, SDA_MODEL_DIGITAL); psxi_sda_init_input(controller, input); diff --git a/frontend/screen.c b/frontend/screen.c index 2b82d2f..fe63c0d 100644 --- a/frontend/screen.c +++ b/frontend/screen.c @@ -1,6 +1,7 @@ #include "screen.h" #include "input/sda.h" +#include "input/guncon.h" uint32_t screen_get_button(SDL_Keycode k) { if (k == SDLK_x ) return PSXI_SW_SDA_CROSS; @@ -356,6 +357,46 @@ void psxe_screen_update(psxe_screen_t* screen) { } } break; + // To-do: GunCon + // case SDL_MOUSEMOTION: { + // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_SX, psx_get_dmode_width(screen->psx)); + // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_SY, psx_get_dmode_height(screen->psx)); + // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_X, event.motion.x * (1.0f / (float)screen->scale)); + // psx_pad_analog_change(screen->pad, 0, PSXI_AX_GUNCON_Y, event.motion.y * (1.0f / (float)screen->scale)); + // } break; + + // case SDL_MOUSEBUTTONDOWN: { + // switch (event.button.button) { + // case SDL_BUTTON_LEFT: { + // psx_pad_button_press(screen->pad, 0, PSXI_SW_GUNCON_A); + // } break; + + // case SDL_BUTTON_RIGHT: { + // psx_pad_button_press(screen->pad, 0, PSXI_SW_GUNCON_B); + // } break; + + // case SDL_BUTTON_MIDDLE: { + // psx_pad_button_press(screen->pad, 0, PSXI_SW_GUNCON_TRIGGER); + // } break; + // } + // } break; + + // case SDL_MOUSEBUTTONUP: { + // switch (event.button.button) { + // case SDL_BUTTON_LEFT: { + // psx_pad_button_release(screen->pad, 0, PSXI_SW_GUNCON_A); + // } break; + + // case SDL_BUTTON_RIGHT: { + // psx_pad_button_release(screen->pad, 0, PSXI_SW_GUNCON_B); + // } break; + + // case SDL_BUTTON_MIDDLE: { + // psx_pad_button_release(screen->pad, 0, PSXI_SW_GUNCON_TRIGGER); + // } break; + // } + // } break; + case SDL_TEXTINPUT: { psx_exp2_atcons_put(screen->psx->exp2, event.text.text[0]); } break; diff --git a/psx/bus.c b/psx/bus.c index 2de1fda..ec9d5ab 100644 --- a/psx/bus.c +++ b/psx/bus.c @@ -104,6 +104,12 @@ uint16_t psx_bus_read16(psx_bus_t* bus, uint32_t addr) { if (addr == 0x1f801054) return 0x05; + if (addr == 0x1f400004) + return 0xc0; + + if (addr == 0x1f400006) + return 0x1fe0; + printf("Unhandled 16-bit read from %08x:%08x\n", vaddr, addr); // exit(1); diff --git a/psx/dev/cdrom.c b/psx/dev/cdrom.c index 1fb9a6f..2fc7b6e 100644 --- a/psx/dev/cdrom.c +++ b/psx/dev/cdrom.c @@ -73,23 +73,24 @@ void cdrom_fetch_video_sector(psx_cdrom_t* cdrom) { msf_add_f(&cdrom->seek_msf, 1); + return; // Check RT and Video/Data bit // if (cdrom->dfifo[0x12] & 4) // continue; // If we get here it means this is a real-time video sector. // If the XA filter is disabled, we're done - if (!(cdrom->mode & MODE_XA_FILTER)) - return; + // if (!(cdrom->mode & MODE_XA_FILTER)) + // return; - // Else check XA file/channel - int file_eq = cdrom->dfifo[0x10] == cdrom->xa_file; - int channel_eq = cdrom->dfifo[0x11] == cdrom->xa_channel; + // // Else check XA file/channel + // int file_eq = cdrom->dfifo[0x10] == cdrom->xa_file; + // int channel_eq = cdrom->dfifo[0x11] == cdrom->xa_channel; - // If they are equal to our filter values, we're done - // else keep searching - if (file_eq && channel_eq) - return; + // // If they are equal to our filter values, we're done + // // else keep searching + // if (file_eq && channel_eq) + // return; } } @@ -921,7 +922,7 @@ void cdrom_cmd_getlocp(psx_cdrom_t* cdrom) { } break; case CD_STATE_SEND_RESP1: { - msf_t absolute = cdrom->xa_playing ? cdrom->xa_msf : cdrom->seek_msf; + msf_t absolute = cdrom->seek_msf; msf_t relative = absolute; msf_t track_msf = cdrom_get_track_addr(cdrom, absolute); @@ -963,7 +964,7 @@ void cdrom_cmd_getlocp(psx_cdrom_t* cdrom) { RESP_PUSH(relative.s); RESP_PUSH(relative.m); RESP_PUSH(0x01); - RESP_PUSH(0x01); + RESP_PUSH(0x15); if (cdrom->ongoing_read_command) { printf("getlocp command=%02x\n", cdrom->ongoing_read_command); @@ -1804,6 +1805,15 @@ void psx_cdrom_init(psx_cdrom_t* cdrom, psx_ic_t* ic) { memset(cdrom->xa_right_resample_buf, 0, (XA_STEREO_RESAMPLE_SIZE * 2) * sizeof(int16_t)); memset(cdrom->xa_mono_resample_buf, 0, (XA_MONO_RESAMPLE_SIZE * 2) * sizeof(int16_t)); + cdrom->vol[0] = 0x80; + cdrom->vol[1] = 0x00; + cdrom->vol[2] = 0x80; + cdrom->vol[3] = 0x00; + cdrom->vapp[0] = 0x80; + cdrom->vapp[1] = 0x00; + cdrom->vapp[2] = 0x80; + cdrom->vapp[3] = 0x00; + cdrom->seek_msf.m = 0; cdrom->seek_msf.s = 2; cdrom->seek_msf.f = 0; diff --git a/psx/dev/gpu.c b/psx/dev/gpu.c index 7d86d0b..1fa40d3 100644 --- a/psx/dev/gpu.c +++ b/psx/dev/gpu.c @@ -6,6 +6,8 @@ #include "gpu.h" #include "../log.h" +#define SE10(v) ((int16_t)((v) << 5) >> 5) + int g_psx_gpu_dither_kernel[] = { -4, +0, -3, +1, +2, -2, +3, -1, @@ -176,6 +178,9 @@ uint16_t gpu_fetch_texel(psx_gpu_t* gpu, uint16_t tx, uint16_t ty, uint32_t tpx, } } +#define TL(z, a, b) \ + ((z < 0) || ((z == 0) && ((b.y > a.y) || ((b.y == a.y) && (b.x < a.x))))) + void gpu_render_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, poly_data_t data, int edge) { vertex_t a, b, c, p; @@ -216,7 +221,7 @@ void gpu_render_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, int xmax = max3(a.x, b.x, c.x); int ymax = max3(a.y, b.y, c.y); - if (((xmax - xmin) > 2048) || ((ymax - ymin) > 1024)) + if (((xmax - xmin) > 2048) || ((ymax - ymin) > 1024)) return; float area = EDGE(a, b, c); @@ -233,24 +238,27 @@ void gpu_render_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, p.y = y; float z0 = EDGE(b, c, p); + + if (TL(z0, b, c)) + continue; + float z1 = EDGE(c, a, p); + + if (TL(z1, c, a)) + continue; + float z2 = EDGE(a, b, p); - int e = ((z0 < 0) || (z1 < 0) || (z2 < 0)); - - if (transp && edge) - e = ((z0 < 0) || (z1 <= 0) || (z2 < 0)); - - if (e) + if (TL(z2, a, b)) continue; uint16_t color = 0; uint32_t mod = 0; if (data.attrib & PA_SHADED) { - int cr = (z0 * ((a.c >> 0) & 0xff) + z1 * ((b.c >> 0) & 0xff) + z2 * ((c.c >> 0) & 0xff)) / area; - int cg = (z0 * ((a.c >> 8) & 0xff) + z1 * ((b.c >> 8) & 0xff) + z2 * ((c.c >> 8) & 0xff)) / area; - int cb = (z0 * ((a.c >> 16) & 0xff) + z1 * ((b.c >> 16) & 0xff) + z2 * ((c.c >> 16) & 0xff)) / area; + float cr = (z0 * ((a.c >> 0) & 0xff) + z1 * ((b.c >> 0) & 0xff) + z2 * ((c.c >> 0) & 0xff)) / area; + float cg = (z0 * ((a.c >> 8) & 0xff) + z1 * ((b.c >> 8) & 0xff) + z2 * ((c.c >> 8) & 0xff)) / area; + float cb = (z0 * ((a.c >> 16) & 0xff) + z1 * ((b.c >> 16) & 0xff) + z2 * ((c.c >> 16) & 0xff)) / area; int dy = (y - ymin) & 3; int dx = (x - xmin) & 3; @@ -262,11 +270,15 @@ void gpu_render_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, cb += dither; // Saturate (clamp) to 00-ff - cr = (cr >= 0xff) ? 0xff : ((cr <= 0) ? 0 : cr); - cg = (cg >= 0xff) ? 0xff : ((cg <= 0) ? 0 : cg); - cb = (cb >= 0xff) ? 0xff : ((cb <= 0) ? 0 : cb); + cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr); + cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg); + cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb); - uint32_t rgb = (cb << 16) | (cg << 8) | cr; + unsigned int ucr = roundf(cr); + unsigned int ucg = roundf(cg); + unsigned int ucb = roundf(cb); + + uint32_t rgb = (ucb << 16) | (ucg << 8) | ucr; mod = rgb; } else { @@ -274,15 +286,15 @@ void gpu_render_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, } if (data.attrib & PA_TEXTURED) { - uint32_t tx = ((z0 * a.tx) + (z1 * b.tx) + (z2 * c.tx)) / area; - uint32_t ty = ((z0 * a.ty) + (z1 * b.ty) + (z2 * c.ty)) / area; + uint32_t tx = roundf(((z0 * a.tx) + (z1 * b.tx) + (z2 * c.tx)) / area); + uint32_t ty = roundf(((z0 * a.ty) + (z1 * b.ty) + (z2 * c.ty)) / area); uint16_t texel = gpu_fetch_texel(gpu, tx, ty, tpx, tpy, clutx, cluty, depth); if (!texel) continue; - if (transp) + if ((data.attrib & PA_TRANSP) != 0) transp = (texel & 0x8000) != 0; if (data.attrib & PA_RAW) { @@ -304,9 +316,9 @@ void gpu_render_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg); cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb); - unsigned int ucr = cr; - unsigned int ucg = cg; - unsigned int ucb = cb; + unsigned int ucr = roundf(cr); + unsigned int ucg = roundf(cg); + unsigned int ucb = roundf(cb); uint32_t rgb = ucr | (ucg << 8) | (ucb << 16); @@ -355,9 +367,9 @@ void gpu_render_triangle(psx_gpu_t* gpu, vertex_t v0, vertex_t v1, vertex_t v2, cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg); cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb); - unsigned int ucr = cr; - unsigned int ucg = cg; - unsigned int ucb = cb; + unsigned int ucr = roundf(cr); + unsigned int ucg = roundf(cg); + unsigned int ucb = roundf(cb); uint32_t rgb = ucr | (ucg << 8) | (ucb << 16); @@ -431,7 +443,7 @@ void gpu_render_rect(psx_gpu_t* gpu, rect_data_t data) { if (!texel) goto skip; - if (transp) + if ((data.attrib & RA_TRANSP) != 0) transp = (texel & 0x8000) != 0; float tr = ((texel >> 0 ) & 0x1f) << 3; @@ -446,9 +458,13 @@ void gpu_render_rect(psx_gpu_t* gpu, rect_data_t data) { float cg = (tg * mg) / 128.0f; float cb = (tb * mb) / 128.0f; - unsigned int ucr = cr; - unsigned int ucg = cg; - unsigned int ucb = cb; + cr = (cr >= 255.0f) ? 255.0f : ((cr <= 0.0f) ? 0.0f : cr); + cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg); + cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb); + + unsigned int ucr = roundf(cr); + unsigned int ucg = roundf(cg); + unsigned int ucb = roundf(cb); uint32_t rgb = ucr | (ucg << 8) | (ucb << 16); @@ -495,9 +511,9 @@ void gpu_render_rect(psx_gpu_t* gpu, rect_data_t data) { cg = (cg >= 255.0f) ? 255.0f : ((cg <= 0.0f) ? 0.0f : cg); cb = (cb >= 255.0f) ? 255.0f : ((cb <= 0.0f) ? 0.0f : cb); - unsigned int ucr = cr; - unsigned int ucg = cg; - unsigned int ucb = cb; + unsigned int ucr = roundf(cr); + unsigned int ucg = roundf(cg); + unsigned int ucb = roundf(cb); uint32_t rgb = ucr | (ucg << 8) | (ucb << 16); @@ -851,8 +867,8 @@ void gpu_rect(psx_gpu_t* gpu) { int size_offset = 2 + textured; rect.v0.c = gpu->buf[0] & 0xffffff; - rect.v0.x = gpu->buf[1] & 0xffff; - rect.v0.y = gpu->buf[1] >> 16; + rect.v0.x = SE10(gpu->buf[1] & 0xffff); + rect.v0.y = SE10(gpu->buf[1] >> 16); rect.v0.tx = (gpu->buf[2] >> 0) & 0xff; rect.v0.ty = (gpu->buf[2] >> 8) & 0xff; rect.clut = gpu->buf[2] >> 16; @@ -903,18 +919,28 @@ void gpu_poly(psx_gpu_t* gpu) { poly.clut = gpu->buf[2] >> 16; poly.texp = gpu->buf[texp_offset] >> 16; + // Undocumented behavior? + // Fixes Mortal Kombat II, Bubble Bobble, Driver 1 & 2 + if (textured) { + gpu->texp_x = (poly.texp & 0xf) << 6; + gpu->texp_y = (poly.texp & 0x10) << 4; + gpu->texp_d = (poly.texp >> 7) & 0x3; + gpu->gpustat &= 0xfffffe00; + gpu->gpustat |= poly.texp & 0x1ff; + } + poly.v[0].c = gpu->buf[0+0*color_offset] & 0xffffff; poly.v[1].c = gpu->buf[0+1*color_offset] & 0xffffff; poly.v[2].c = gpu->buf[0+2*color_offset] & 0xffffff; poly.v[3].c = gpu->buf[0+3*color_offset] & 0xffffff; - poly.v[0].x = gpu->buf[1+0*vert_offset] & 0xffff; - poly.v[1].x = gpu->buf[1+1*vert_offset] & 0xffff; - poly.v[2].x = gpu->buf[1+2*vert_offset] & 0xffff; - poly.v[3].x = gpu->buf[1+3*vert_offset] & 0xffff; - poly.v[0].y = gpu->buf[1+0*vert_offset] >> 16; - poly.v[1].y = gpu->buf[1+1*vert_offset] >> 16; - poly.v[2].y = gpu->buf[1+2*vert_offset] >> 16; - poly.v[3].y = gpu->buf[1+3*vert_offset] >> 16; + poly.v[0].x = SE10(gpu->buf[1+0*vert_offset] & 0xffff); + poly.v[1].x = SE10(gpu->buf[1+1*vert_offset] & 0xffff); + poly.v[2].x = SE10(gpu->buf[1+2*vert_offset] & 0xffff); + poly.v[3].x = SE10(gpu->buf[1+3*vert_offset] & 0xffff); + poly.v[0].y = SE10(gpu->buf[1+0*vert_offset] >> 16); + poly.v[1].y = SE10(gpu->buf[1+1*vert_offset] >> 16); + poly.v[2].y = SE10(gpu->buf[1+2*vert_offset] >> 16); + poly.v[3].y = SE10(gpu->buf[1+3*vert_offset] >> 16); poly.v[0].tx = gpu->buf[2+0*texc_offset] & 0xff; poly.v[1].tx = gpu->buf[2+1*texc_offset] & 0xff; poly.v[2].tx = gpu->buf[2+2*texc_offset] & 0xff; @@ -925,7 +951,7 @@ void gpu_poly(psx_gpu_t* gpu) { poly.v[3].ty = (gpu->buf[2+3*texc_offset] >> 8) & 0xff; if (poly.attrib & PA_QUAD) { - gpu_render_triangle(gpu, poly.v[0], poly.v[1], poly.v[2], poly, 0); + gpu_render_triangle(gpu, poly.v[0], poly.v[1], poly.v[2], poly, 1); gpu_render_triangle(gpu, poly.v[1], poly.v[2], poly.v[3], poly, 1); } else { gpu_render_triangle(gpu, poly.v[0], poly.v[1], poly.v[2], poly, 0); @@ -1647,8 +1673,8 @@ void psx_gpu_update_cmd(psx_gpu_t* gpu) { gpu->draw_y2 = (gpu->buf[0] >> 10) & 0x1ff; } break; case 0xe5: { - gpu->off_x = ((int32_t)((gpu->buf[0] >> 0 ) & 0x7ff) << 21) >> 21; - gpu->off_y = ((int32_t)((gpu->buf[0] >> 11) & 0x7ff) << 21) >> 21; + gpu->off_x = ((int32_t)(((gpu->buf[0] >> 0 ) & 0x7ff) << 21)) >> 21; + gpu->off_y = ((int32_t)(((gpu->buf[0] >> 11) & 0x7ff) << 21)) >> 21; } break; case 0xe6: { /* To-do: Implement mask bit thing */ diff --git a/psx/dev/input.h b/psx/dev/input.h index 6ade28d..115c61c 100644 --- a/psx/dev/input.h +++ b/psx/dev/input.h @@ -11,7 +11,7 @@ typedef void (*psx_input_write_t)(void*, uint16_t); typedef uint32_t (*psx_input_read_t)(void*); typedef void (*psx_input_on_button_press_t)(void*, uint32_t); typedef void (*psx_input_on_button_release_t)(void*, uint32_t); -typedef void (*psx_input_on_analog_change_t)(void*, uint32_t, uint8_t); +typedef void (*psx_input_on_analog_change_t)(void*, uint32_t, uint16_t); typedef int (*psx_input_query_fifo_t)(void*); struct psx_input_t { diff --git a/psx/dev/pad.c b/psx/dev/pad.c index 0a61c0f..65ed49b 100644 --- a/psx/dev/pad.c +++ b/psx/dev/pad.c @@ -262,7 +262,7 @@ void psx_pad_button_release(psx_pad_t* pad, int slot, uint32_t data) { selected_slot->on_button_release_func(selected_slot->udata, data); } -void psx_pad_analog_change(psx_pad_t* pad, int slot, uint32_t stick, uint8_t data) { +void psx_pad_analog_change(psx_pad_t* pad, int slot, uint32_t stick, uint16_t data) { psx_input_t* selected_slot = pad->joy_slot[slot]; if (selected_slot) diff --git a/psx/dev/pad.h b/psx/dev/pad.h index 8a87baa..700eadb 100644 --- a/psx/dev/pad.h +++ b/psx/dev/pad.h @@ -131,7 +131,7 @@ void psx_pad_write8(psx_pad_t*, uint32_t, uint8_t); void psx_pad_destroy(psx_pad_t*); void psx_pad_button_press(psx_pad_t*, int, uint32_t); void psx_pad_button_release(psx_pad_t*, int, uint32_t); -void psx_pad_analog_change(psx_pad_t*, int, uint32_t, uint8_t); +void psx_pad_analog_change(psx_pad_t*, int, uint32_t, uint16_t); void psx_pad_attach_joy(psx_pad_t*, int, psx_input_t*); void psx_pad_detach_joy(psx_pad_t*, int); void psx_pad_attach_mcd(psx_pad_t*, int, const char*); diff --git a/psx/dev/ram.c b/psx/dev/ram.c index b03de43..90deded 100644 --- a/psx/dev/ram.c +++ b/psx/dev/ram.c @@ -9,50 +9,53 @@ psx_ram_t* psx_ram_create(void) { return (psx_ram_t*)malloc(sizeof(psx_ram_t)); } -void psx_ram_init(psx_ram_t* ram, psx_mc2_t* mc2) { +void psx_ram_init(psx_ram_t* ram, psx_mc2_t* mc2, int size) { memset(ram, 0, sizeof(psx_ram_t)); ram->io_base = PSX_RAM_BEGIN; ram->io_size = PSX_RAM_SIZE; ram->mc2 = mc2; - ram->buf = (uint8_t*)malloc(PSX_RAM_SIZE); + ram->buf = (uint8_t*)malloc(RAM_SIZE); - memset(ram->buf, 0xee, PSX_RAM_SIZE); + if (size & 0x1ffff) + size = RAM_SIZE_2MB; + + memset(ram->buf, RAM_INIT_FILL, size); } uint32_t psx_ram_read32(psx_ram_t* ram, uint32_t offset) { - offset &= 0x1fffff; + offset &= RAM_SIZE - 1; return *((uint32_t*)(ram->buf + offset)); } uint16_t psx_ram_read16(psx_ram_t* ram, uint32_t offset) { - offset &= 0x1fffff; + offset &= RAM_SIZE - 1; return *((uint16_t*)(ram->buf + offset)); } uint8_t psx_ram_read8(psx_ram_t* ram, uint32_t offset) { - offset &= 0x1fffff; + offset &= RAM_SIZE - 1; return ram->buf[offset]; } void psx_ram_write32(psx_ram_t* ram, uint32_t offset, uint32_t value) { - offset &= 0x1fffff; + offset &= RAM_SIZE - 1; *((uint32_t*)(ram->buf + offset)) = value; } void psx_ram_write16(psx_ram_t* ram, uint32_t offset, uint16_t value) { - offset &= 0x1fffff; + offset &= RAM_SIZE - 1; *((uint16_t*)(ram->buf + offset)) = value; } void psx_ram_write8(psx_ram_t* ram, uint32_t offset, uint8_t value) { - offset &= 0x1fffff; + offset &= RAM_SIZE - 1; ram->buf[offset] = value; } diff --git a/psx/dev/ram.h b/psx/dev/ram.h index b4a43fc..f059976 100644 --- a/psx/dev/ram.h +++ b/psx/dev/ram.h @@ -6,11 +6,16 @@ #include "../log.h" #include "mc2.h" -//#define PSX_RAM_SIZE 0x200000 +#define RAM_SIZE 0x200000 #define PSX_RAM_SIZE 0x1f000000 #define PSX_RAM_BEGIN 0x00000000 //#define PSX_RAM_END 0x001fffff #define PSX_RAM_END 0x1effffff +#define RAM_INIT_FILL 0 + +#define RAM_SIZE_2MB 0x200000 +#define RAM_SIZE_4MB 0x400000 +#define RAM_SIZE_8MB 0x800000 typedef struct { uint32_t bus_delay; @@ -22,7 +27,7 @@ typedef struct { } psx_ram_t; psx_ram_t* psx_ram_create(void); -void psx_ram_init(psx_ram_t*, psx_mc2_t*); +void psx_ram_init(psx_ram_t*, psx_mc2_t*, int size); uint32_t psx_ram_read32(psx_ram_t*, uint32_t); uint16_t psx_ram_read16(psx_ram_t*, uint32_t); uint8_t psx_ram_read8(psx_ram_t*, uint32_t); diff --git a/psx/input/guncon.c b/psx/input/guncon.c new file mode 100644 index 0000000..afa2012 --- /dev/null +++ b/psx/input/guncon.c @@ -0,0 +1,138 @@ +/* + This file is part of the PSXE Emulator Project + + Sony PlayStation Standard Digital/Analog Controller Emulator +*/ + +#include "guncon.h" +#include "../log.h" + +#include +#include + +const char* states[] = { + "HIZ", + "IDL", + "IDH", + "SWL", + "SWH", + "XPL", + "XPH", + "YPL", + "YPH" +}; + +psxi_guncon_t* psxi_guncon_create(void) { + return (psxi_guncon_t*)malloc(sizeof(psxi_guncon_t)); +} + +void psxi_guncon_init(psxi_guncon_t* guncon) { + memset(guncon, 0, sizeof(psxi_guncon_t)); + + guncon->tx_data = 0xff; + guncon->tx_data_ready = 1; + guncon->state = GUNCON_STATE_TX_HIZ; + guncon->sw = 0xffff; + guncon->x = 0x4d; + guncon->y = 0x19; + guncon->sx = 384; + guncon->sy = 240; +} + +uint32_t psxi_guncon_read(void* udata) { + psxi_guncon_t* guncon = (psxi_guncon_t*)udata; + + switch (guncon->state) { + case GUNCON_STATE_TX_HIZ: guncon->tx_data = 0xff; break; + case GUNCON_STATE_TX_IDL: guncon->tx_data = GUNCON_IDL; break; + case GUNCON_STATE_TX_IDH: guncon->tx_data = GUNCON_IDH; break; + case GUNCON_STATE_TX_SWL: guncon->tx_data = guncon->sw & 0xff; break; + case GUNCON_STATE_TX_SWH: guncon->tx_data = guncon->sw >> 8; break; + case GUNCON_STATE_TX_XPL: guncon->tx_data = guncon->x & 0xff; break; + case GUNCON_STATE_TX_XPH: guncon->tx_data = guncon->x >> 8; break; + case GUNCON_STATE_TX_YPL: guncon->tx_data = guncon->y & 0xff; break; + case GUNCON_STATE_TX_YPH: { + // printf("guncon: read state %u (%s) -> %02x\n", guncon->state, states[guncon->state], guncon->y >> 8); + + guncon->tx_data_ready = 0; + guncon->state = GUNCON_STATE_TX_HIZ; + + return guncon->y >> 8; + } break; + } + + // printf("guncon: read state %u (%s) -> %02x\n", guncon->state, states[guncon->state], guncon->tx_data); + + guncon->tx_data_ready = 1; + guncon->state++; + + return guncon->tx_data; +} + +void psxi_guncon_write(void* udata, uint16_t data) { + psxi_guncon_t* guncon = (psxi_guncon_t*)udata; + + // printf("guncon: write %02x\n", data); + + (void)guncon; +} + +void psxi_guncon_on_button_press(void* udata, uint32_t data) { + psxi_guncon_t* guncon = (psxi_guncon_t*)udata; + + guncon->sw &= ~data; +} + +void psxi_guncon_on_button_release(void* udata, uint32_t data) { + psxi_guncon_t* guncon = (psxi_guncon_t*)udata; + + guncon->sw |= data; +} + +void psxi_guncon_on_analog_change(void* udata, uint32_t axis, uint16_t data) { + psxi_guncon_t* guncon = (psxi_guncon_t*)udata; + + switch (axis) { + case PSXI_AX_GUNCON_X: { + data *= (461.0f - 77.0f) / (float)guncon->sx; + data += 77; + + guncon->x = data; + } break; + + case PSXI_AX_GUNCON_Y: { + data *= (248.0f - 25.0f) / (float)guncon->sy; + data += 25; + + guncon->y = data; + } break; + + case PSXI_AX_GUNCON_SX: { + guncon->sx = data; + } break; + + case PSXI_AX_GUNCON_SY: { + guncon->sy = data; + } break; + } +} + +int psxi_guncon_query_fifo(void* udata) { + psxi_guncon_t* guncon = (psxi_guncon_t*)udata; + + return guncon->tx_data_ready; +} + +void psxi_guncon_init_input(psxi_guncon_t* guncon, psx_input_t* input) { + input->udata = guncon; + input->write_func = psxi_guncon_write; + input->read_func = psxi_guncon_read; + input->on_button_press_func = psxi_guncon_on_button_press; + input->on_button_release_func = psxi_guncon_on_button_release; + input->on_analog_change_func = psxi_guncon_on_analog_change; + input->query_fifo_func = psxi_guncon_query_fifo; +} + +void psxi_guncon_destroy(psxi_guncon_t* guncon) { + free(guncon); +} \ No newline at end of file diff --git a/psx/input/guncon.h b/psx/input/guncon.h new file mode 100644 index 0000000..59e1429 --- /dev/null +++ b/psx/input/guncon.h @@ -0,0 +1,67 @@ +/* + This file is part of the PSXE Emulator Project + + Namco GunCon emulation +*/ + +#ifndef GUNCON_H +#define GUNCON_H + +#include "../dev/input.h" + +/* + __Halfword 0 (Controller Info)___________________ + 0-15 Controller Info (5A63h=Namco Lightgun; GunCon/Cinch Type) + __Halfword 1 (Buttons)___________________________ + 0-2 Not used (All bits always 1) + 3 Button A (Left Side) (0=Pressed, 1=Released) ;aka Joypad Start + 4-12 Not used (All bits always 1) + 13 Trigger Button (0=Pressed, 1=Released) ;aka Joypad O-Button + 14 Button B (Right Side) (0=Pressed, 1=Released) ;aka Joypad X-Button + 15 Not used (All bits always 1) + __Halfword 2 (X)_________________________________ + 0-15 8MHz clks since HSYNC (01h=Error, or 04Dh..1CDh) + __Halfword 3 (Y)_________________________________ + 0-15 Scanlines since VSYNC (05h/0Ah=Error, PAL=20h..127h, NTSC=19h..F8h) +*/ + +#define GUNCON_IDL 0x63 +#define GUNCON_IDH 0x5a + +#define PSXI_SW_GUNCON_A 0x00000008 +#define PSXI_SW_GUNCON_TRIGGER 0x00002000 +#define PSXI_SW_GUNCON_B 0x00004000 +#define PSXI_AX_GUNCON_X 0x00010000 +#define PSXI_AX_GUNCON_Y 0x00020000 +#define PSXI_AX_GUNCON_SX 0x00030000 +#define PSXI_AX_GUNCON_SY 0x00040000 + +enum { + GUNCON_STATE_TX_HIZ = 0, + GUNCON_STATE_TX_IDL, + GUNCON_STATE_TX_IDH, + GUNCON_STATE_TX_SWL, + GUNCON_STATE_TX_SWH, + GUNCON_STATE_TX_XPL, + GUNCON_STATE_TX_XPH, + GUNCON_STATE_TX_YPL, + GUNCON_STATE_TX_YPH +}; + +typedef struct { + int state; + uint16_t sw; + uint8_t tx_data; + int tx_data_ready; + uint16_t x; + uint16_t y; + uint16_t sx; + uint16_t sy; +} psxi_guncon_t; + +psxi_guncon_t* psxi_guncon_create(void); +void psxi_guncon_init(psxi_guncon_t*); +void psxi_guncon_init_input(psxi_guncon_t*, psx_input_t*); +void psxi_guncon_destroy(psxi_guncon_t*); + +#endif \ No newline at end of file diff --git a/psx/input/sda.c b/psx/input/sda.c index 148566a..ec0e94a 100644 --- a/psx/input/sda.c +++ b/psx/input/sda.c @@ -122,7 +122,7 @@ void psxi_sda_on_button_release(void* udata, uint32_t data) { } // To-do: Implement analog mode -void psxi_sda_on_analog_change(void* udata, uint32_t axis, uint8_t data) { +void psxi_sda_on_analog_change(void* udata, uint32_t axis, uint16_t data) { // Suppress warning until we implement analog mode psxi_sda_t* sda = (psxi_sda_t*)udata; diff --git a/psx/psx.c b/psx/psx.c index 5fa3ab6..137588f 100644 --- a/psx/psx.c +++ b/psx/psx.c @@ -167,7 +167,7 @@ void psx_init(psx_t* psx, const char* bios_path, const char* exp_path) { psx_mc1_init(psx->mc1); psx_mc2_init(psx->mc2); psx_mc3_init(psx->mc3); - psx_ram_init(psx->ram, psx->mc2); + psx_ram_init(psx->ram, psx->mc2, RAM_SIZE_2MB); psx_dma_init(psx->dma, psx->bus, psx->ic); psx_exp1_init(psx->exp1, psx->mc1, exp_path); psx_exp2_init(psx->exp2, atcons_tx, NULL);